1 /*****************************************************************************\
2 printer.cpp : Implimentation for the Printer class
4 Copyright (c) 1996 - 2006, Hewlett-Packard Co.
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
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.
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 \*****************************************************************************/
34 #include "resources.h"
38 // ** Printer CLASS **
41 extern BYTE* GetHTBinary();
52 constructor_error(NO_ERROR),
54 #if defined(APDK_FONTS_NEEDED)
59 bCheckForCancelButton(FALSE),
60 ulBytesSentSinceCancelCheck(0),
65 iTotal_SLOW_POLL_Count(0),
66 iMax_SLOW_POLL_Count(DEFAULT_SLOW_POLL_COUNT),
67 ErrorTerminationState(FALSE),
68 iBuffSize(pSys->GetSendBufferSize()),
81 for (i = 0; i < MAX_PRINTMODES; i++)
86 //CompatiblePens[0] = BOTH_PENS;
87 //for (i = 1; i < MAX_COMPATIBLE_PENS; i++)
89 // CompatiblePens[i] = DUMMY_PEN;
94 iMax_SLOW_POLL_Count = DEFAULT_SLOW_POLL_BIDI;
97 // Allocate memory for my send buffer
99 #ifdef APDK_BUFFER_SEND
100 pSendBuffer = pSS->AllocMem(iBuffSize+2);
101 CNEWCHECK(pSendBuffer);
104 #ifdef APDK_AUTODUPLEX
105 bDuplexCapable = FALSE;
106 m_bRotateBackPage = TRUE;
110 * LaserJet printers do not send status via device id string. PJL is used to
112 * REVISIT: Do the same for Business Inkjets as well.
115 m_bStatusByPJL = FALSE;
117 if ((strstr ((char *) pSS->strDevID, "LaserJet")) &&
118 (tmpStr = strstr ((char *) pSS->strDevID, "CMD:")) &&
119 (tmpStr = strstr (tmpStr+4, "PJL")))
121 m_bStatusByPJL = TRUE;
124 #if defined(APDK_FONTS_NEEDED)
125 // create dummy font objects to be queried via EnumFont
126 // these fonts used by all except DJ400
128 for (i = 0; i<=MAX_PRINTER_FONTS; i++)
133 fontarray[COURIER_INDEX] = new Courier();
134 CNEWCHECK(fontarray[COURIER_INDEX]);
137 fontarray[CGTIMES_INDEX] = new CGTimes();
138 CNEWCHECK(fontarray[CGTIMES_INDEX]);
140 #ifdef APDK_LTRGOTHIC
141 fontarray[LETTERGOTHIC_INDEX] = new LetterGothic();
142 CNEWCHECK(fontarray[LETTERGOTHIC_INDEX]);
145 fontarray[UNIVERS_INDEX] = new Univers();
146 CNEWCHECK(fontarray[UNIVERS_INDEX]);
155 if (pMode[GRAYMODE_INDEX])
157 if (pMode[GRAYMODE_INDEX]->dyeCount==3) // only happens when compgray map used
159 pSS->FreeMem((BYTE*) pMode[GRAYMODE_INDEX]->cmap.ulMap1 );
163 for (int i = 0; i < MAX_PRINTMODES; i++)
171 #ifdef APDK_BUFFER_SEND
172 if (pSendBuffer != NULL)
174 pSS->FreeMem(pSendBuffer);
179 delete fontarray[COURIER_INDEX];
182 delete fontarray[CGTIMES_INDEX];
184 #ifdef APDK_LTRGOTHIC
185 delete fontarray[LETTERGOTHIC_INDEX];
188 delete fontarray[UNIVERS_INDEX];
194 ////////////////////////////////////////////////////////////////////////////
195 Compressor* Printer::CreateCompressor (unsigned int RasterSize)
197 return new Mode9 (pSS, RasterSize); // most printers use mode 9
200 ////////////////////////////////////////////////////////////////////////////
201 Compressor* Printer::CreateBlackPlaneCompressor (unsigned int RasterSize,
204 return new Mode9 (pSS, RasterSize, bVIPPrinter); // most printers use mode 9
207 ////////////////////////////////////////////////////////////////////////////
212 DRIVER_ERROR Printer::Flush
214 int FlushSize // = MAX_RASTERSIZE
216 // flush possible leftover garbage --
217 // default call will send one (maximal) raster's worth of zeroes
219 ASSERT(FlushSize > 0);
220 ASSERT(FlushSize <= MAX_RASTERSIZE);
222 DRIVER_ERROR err = NO_ERROR;
223 int iChunkSize = 1000;
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)
233 zero = pSS->AllocMem(iChunkSize);
242 return ALLOCMEM_ERROR;
245 memset(zero, 0, iChunkSize);
246 int iChunks = (FlushSize / iChunkSize) + 1;
248 for (int i = 0; i < iChunks; i++)
250 if ((err = Send( zero, iChunkSize)) != NO_ERROR)
252 break; // there was an error
255 pSS->FreeMem(zero); //break to here
261 * Function name: ParseError
263 * Owner: Darrell Walker
265 * Purpose: To determine what error state the printer is in.
269 * Parameters on entry: status_reg is the contents of the centronics
270 * status register (at the time the error was
273 * Parameters on exit: unchanged
275 * Return Values: The proper DISPLAY_STATUS to reflect the printer
280 DISPLAY_STATUS Printer::ParseError
285 DBG1("Printer: parsing error info\n");
287 DRIVER_ERROR err = NO_ERROR;
288 BYTE DevIDBuffer[DevIDBuffSize];
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);
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;
303 // check for errors we can detect from the status reg
307 if ( DEVICE_IS_OOP(status_reg) )
309 DBG1("Out Of Paper\n");
310 return DISPLAY_OUT_OF_PAPER;
313 if (DEVICE_PAPER_JAMMED(status_reg))
315 DBG1("Paper Jammed\n");
316 return DISPLAY_PAPER_JAMMED;
318 if (DEVICE_IO_TRAP(status_reg))
321 return DISPLAY_ERROR_TRAP;
327 if ( TopCoverOpen(status_reg) )
329 DBG1("Top Cover Open\n");
330 return DISPLAY_TOP_COVER_OPEN;
333 // VerifyPenInfo will handle prompting the user
334 // if this is a problem
338 // don't know what the problem is-
339 // Is the PrinterAlive?
340 if (pSS->PrinterIsAlive()) // <- This is only viable if bStatus is TRUE
342 iTotal_SLOW_POLL_Count += iMax_SLOW_POLL_Count;
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.
350 // REVISIT these counts - they are relative to the speed through
351 // the send loop aren't they? They may be too long!
353 ((IOMode.bDevID == FALSE) && (iTotal_SLOW_POLL_Count >= 60)) ||
354 ((IOMode.bDevID == TRUE) && (iTotal_SLOW_POLL_Count >= 120))
361 return DISPLAY_PRINTING;
366 return DISPLAY_COMM_PROBLEM;
370 DRIVER_ERROR Printer::Encapsulate
372 const RASTERDATA* InputRaster,
384 if (InputRaster->rastersize[COLORTYPE_BLACK] != 0)
386 if (InputRaster->rastersize[COLORTYPE_COLOR] != 0)
388 scratchLen = sprintf (scratch, "\033*b%uV", InputRaster->rastersize[COLORTYPE_BLACK]);
389 err = Send ((const BYTE*) scratch, scratchLen);
392 err = Send (InputRaster->rasterdata[COLORTYPE_BLACK], InputRaster->rastersize[COLORTYPE_BLACK]);
396 scratchLen = sprintf (scratch, "\033*b%uW", InputRaster->rastersize[COLORTYPE_COLOR]);
397 err = Send ((const BYTE*) scratch, scratchLen);
400 err = Send (InputRaster->rasterdata[COLORTYPE_COLOR], InputRaster->rastersize[COLORTYPE_COLOR]);
406 scratchLen = sprintf (scratch, "\033*b%uV", InputRaster->rastersize[COLORTYPE_BLACK]);
407 err = Send ((const BYTE*) scratch, scratchLen);
410 err = Send (InputRaster->rasterdata[COLORTYPE_BLACK], InputRaster->rastersize[COLORTYPE_BLACK]);
413 scratchLen = sprintf (scratch, "\033*b%uW", 0);
414 err = Send ((const BYTE*) scratch, scratchLen);
421 scratchLen = sprintf (scratch, "\033*b%uV", 0);
422 err = Send ((const BYTE*) scratch, scratchLen);
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)
429 err = Send (InputRaster->rasterdata[COLORTYPE_COLOR], InputRaster->rastersize[COLORTYPE_COLOR]);
436 scratchLen = sprintf (scratch, "\033*b%uW", InputRaster->rastersize[COLORTYPE_COLOR]);
437 err = Send ((const BYTE*) scratch, scratchLen);
440 err = Send (InputRaster->rasterdata[COLORTYPE_COLOR], InputRaster->rastersize[COLORTYPE_COLOR]);
446 scratchLen = sprintf (scratch, "\033*b%uV", InputRaster->rastersize[COLORTYPE_COLOR]);
447 err = Send ((const BYTE*) scratch, scratchLen);
450 err = Send (InputRaster->rasterdata[COLORTYPE_COLOR], InputRaster->rastersize[COLORTYPE_COLOR]);
457 DRIVER_ERROR Printer::Send
459 const BYTE* pWriteBuff
463 int len = strlen((const char*)pWriteBuff);
464 return Send(pWriteBuff,len);
469 * Function name: Printer::Send
471 * Owner: Darrell Walker
473 * Purpose: Encapsulate error handling generated by performing I/O
477 * Calls made: WritePort(), GetStatus(), BusyWait(), ParseError(),
478 * DisplayPrinterStatus(), YieldToSystem()
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
486 * Parameters on exit: Unchanged
488 * Side effects: Sends data to the printer, may update print dialog,
489 * may change pJob->InSlowPollMode,
490 * pJob->ErrorTerminationState
492 * Return Values: NO_ERROR or JOB_CANCELED or IO_ERROR
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.
505 DRIVER_ERROR Printer::Send
507 const BYTE* pWriteBuff,
513 DRIVER_ERROR write_error = NO_ERROR;
515 const BYTE * pWritePos = NULL;
516 BOOL error_displayed = FALSE;
518 DISPLAY_STATUS eDisplayStatus = DISPLAY_PRINTING;
519 BOOL JobCanceled = FALSE; // see comments in function header
521 // these are just an abstraction layer - buffered vs. non-buffered
522 const BYTE * pBuffer = pWriteBuff;
523 DWORD dwSendSize = dwWriteCount;
525 ////////////////////////////////////////////////////////////////
527 // test imaging speed independent of printer I/O, will not
528 // send any data to the device
531 ////////////////////////////////////////////////////////////////
533 if (ErrorTerminationState) // don't try any more IO if we previously
535 return JOB_CANCELED; // terminated in an error state
538 if (EndJob == FALSE && dwWriteCount == 0) // don't bother processing
540 return NO_ERROR; // an empty Send call
543 #ifdef APDK_BUFFER_SEND
544 DWORD BytesToWrite = dwWriteCount;
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) )
551 pBuffer = pWriteBuff+(dwWriteCount-BytesToWrite);
552 dwSendSize = BytesToWrite;
553 BytesToWrite = 0; // this is checked for at the end of the outer loop
555 else // we will buffer this data
557 // if it'll fit then just copy everything to the buffer
558 if (BytesToWrite <= DWORD(iBuffSize-iCurrBuffSize))
560 memcpy((void*)(pSendBuffer+iCurrBuffSize),
561 (void*)(pWriteBuff+(dwWriteCount-BytesToWrite)),BytesToWrite);
562 iCurrBuffSize += BytesToWrite;
565 else // copy what we can into the buffer, we'll get the rest later
567 memcpy((void*)(pSendBuffer+iCurrBuffSize),
568 (void*)(pWriteBuff+(dwWriteCount-BytesToWrite)),
569 iBuffSize-iCurrBuffSize);
570 BytesToWrite -= (iBuffSize-iCurrBuffSize);
571 iCurrBuffSize = iBuffSize;
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) )
579 break; // we're not ready to send yet
581 else // send this buffered data
583 pBuffer = pSendBuffer;
584 dwSendSize = iCurrBuffSize;
589 // initialize our 'residual' to the full send size
590 residual = dwSendSize;
592 if (bCheckForCancelButton &&
593 (ulBytesSentSinceCancelCheck >= CANCEL_BUTTON_CHECK_THRESHOLD) &&
\r
594 (pSS->IOMode.bDevID))
596 ulBytesSentSinceCancelCheck = 0;
598 BYTE DevIDBuffer[DevIDBuffSize];
599 DRIVER_ERROR tmpErr = pSS->GetDeviceID(DevIDBuffer, DevIDBuffSize, TRUE);
602 BOOL cancelcheck=FALSE;
604 if((tmpStr = strstr((char*)DevIDBuffer + 2,"CNCL")))
610 int iVersion = pSS->GetVIPVersion ();
612 if((tmpStr = strstr((char*)DevIDBuffer + 2,";S:")) &&
613 iVersion < 6) // DJ990 devID style
615 // point to PrinterState
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
624 tmpStr += 17; // 3 for ";S:", 2 for version, 12 for features = 17
626 else if (iVersion < 5)
628 tmpStr += 19; // 17 as above plus 1 for MaxPaperSize, 1 reserved = 19
632 tmpStr += 23; // Crystal added 4 more nibbles
637 if (((b1=='0') && (b2=='5')) && iVersion <= 5) // 05 = cancel
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);
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.
662 while (residual > 0) // while still data to send in this request
664 DWORD prev_residual = residual; // WritePort overwrites request
665 // count, need to save
667 pWritePos = (const BYTE *) &(pBuffer[dwSendSize-residual]);
668 write_error = pSS->ToDevice(pWritePos, &residual);
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)
680 // DBG1("IO_ERROR returned from ToDevice - ABORT!\n");
681 // ErrorTerminationState = TRUE;
682 // return write_error;
685 write_error = NO_ERROR;
686 eDisplayStatus = DISPLAY_PRINTING;
687 if (residual == 0) // no more data to send this time
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;
698 // did we want to transition out of slow poll?
699 if ( (InSlowPollMode != 0) &&
700 (prev_residual > MIN_XFER_FOR_SLOW_POLL) )
703 iTotal_SLOW_POLL_Count = 0;
705 if (write_error == NO_ERROR)
706 break; // out of while loop
710 // if we are here, WritePort() was not able to
711 // send the full request so start looking for errors
713 // decide whether we've waited long enough to check for an error
714 if (InSlowPollMode > iMax_SLOW_POLL_Count )
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.
720 DBG1("Send(SlowPoll): Premature return w/ JOB_CANCELED\n");
721 ErrorTerminationState = TRUE;
725 DBG1("Printer slow poll times exceeded\n");
726 // reset counter so we will not pop it next time
728 write_error = IO_ERROR;
732 write_error = NO_ERROR;
735 // are we in slow poll mode? If so, track our count
736 if ( (prev_residual - residual) <= MIN_XFER_FOR_SLOW_POLL)
740 #if defined(DEBUG) && (DBG_MASK & DBG_LVL1)
741 if (InSlowPollMode == 1)
743 printf("entering slow poll mode\n");
747 printf("still in slow poll mode, count = %d\n",
751 // give the printer some time to process
752 if (pSS->BusyWait((DWORD)200) == JOB_CANCELED)
754 DBG1("Send: JOB_CANCELED\n");
756 pSS->DisplayPrinterStatus(DISPLAY_PRINTING_CANCELED);
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");
765 iTotal_SLOW_POLL_Count = 0;
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...
773 DBG1("Parsing possible error state...\n");
774 error_displayed = TRUE;
778 status_reg = (BYTE) eDisplayStatus;
782 // go get the status of the printer
785 pSS->GetStatusInfo(&status_reg);
788 // determine the error
789 eDisplayStatus = ParseError(status_reg);
792 switch (eDisplayStatus)
794 case DISPLAY_PRINTING_CANCELED:
796 // user canceled in an error state,
797 // so we don't want to attempt any
798 // further communication with the printer
800 ErrorTerminationState = TRUE;
801 pSS->DisplayPrinterStatus(eDisplayStatus);
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
810 ErrorTerminationState = TRUE;
811 pSS->DisplayPrinterStatus(eDisplayStatus);
813 // wait for user to cancel the job,
814 // otherwise they might miss the
816 while (pSS->BusyWait(500) != JOB_CANCELED)
823 case DISPLAY_TOP_COVER_OPEN:
825 pSS->DisplayPrinterStatus(DISPLAY_TOP_COVER_OPEN);
827 // wait for top cover to close
828 while ( eDisplayStatus == DISPLAY_TOP_COVER_OPEN)
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.
834 ErrorTerminationState = TRUE;
840 status_reg = (BYTE) eDisplayStatus;
846 pSS->GetStatusInfo(&status_reg);
850 eDisplayStatus = ParseError(status_reg);
853 pSS->DisplayPrinterStatus(DISPLAY_PRINTING);
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.
861 DBG1("Send: JOB_CANCELED\n");
863 pSS->DisplayPrinterStatus(DISPLAY_PRINTING_CANCELED);
868 case DISPLAY_OUT_OF_PAPER:
869 case DISPLAY_PHOTOTRAY_MISMATCH:
871 DISPLAY_STATUS tmpStatus = eDisplayStatus;
872 pSS->DisplayPrinterStatus(eDisplayStatus);
874 // wait for the user to add paper and
876 while ( eDisplayStatus == tmpStatus)
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.
882 ErrorTerminationState = TRUE;
888 status_reg = (BYTE) eDisplayStatus;
894 pSS->GetStatusInfo(&status_reg);
898 eDisplayStatus = ParseError(status_reg);
901 pSS->DisplayPrinterStatus(DISPLAY_PRINTING);
908 if (pSS->BusyWait((DWORD)5000) == JOB_CANCELED)
910 ErrorTerminationState = TRUE;
914 pSS->DisplayPrinterStatus(DISPLAY_BUSY);
918 // other cases need no special handling, display
919 // the error and try to continue
921 pSS->DisplayPrinterStatus(eDisplayStatus);
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)
930 DBG1("Send: JOB_CANCELED\n");
932 pSS->DisplayPrinterStatus(DISPLAY_PRINTING_CANCELED);
935 } // while (residual > 0)
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)
943 pSS->DisplayPrinterStatus(DISPLAY_PRINTING_CANCELED);
946 #ifdef APDK_BUFFER_SEND
947 // Our buffer is now empty: reset the size so concurrent writes start at the beginning
950 } while (BytesToWrite > 0);
953 // restore my JOB_CANCELED error
954 if (JobCanceled == TRUE)
956 DBG1("Send: Clean return w/ JOB_CANCELED\n");
957 // ensure that display still says we're cancelling
958 pSS->DisplayPrinterStatus(DISPLAY_PRINTING_CANCELED);
963 // ensure any error message has been cleared
964 pSS->DisplayPrinterStatus(DISPLAY_PRINTING);
965 if (bCheckForCancelButton)
967 ulBytesSentSinceCancelCheck += dwWriteCount;
974 BOOL Printer::TopCoverOpen
980 BYTE bDevIDBuff[DevIDBuffSize];
982 if(IOMode.bDevID == FALSE)
987 DRIVER_ERROR err = pSS->GetDeviceID(bDevIDBuff, DevIDBuffSize, TRUE);
993 if( (pStr=strstr((char*)bDevIDBuff+2,"VSTATUS:")) ) // find the VSTATUS area
996 // now parse VSTATUS parameters
997 // looking for UP for open, DN for closed
998 if (strstr((char*)pStr,"UP"))
1002 if (strstr((char*)pStr,"DN"))
1007 DBG1("didn't find UP or DN!!\n");
1011 if (( pStr = strstr ((char*) bDevIDBuff+2, ";S")))
1013 if ( (*(pStr+5) == '9') )
1024 return FALSE; // if we can't find VSTATUS or binary status field, assume top is not open
1029 DRIVER_ERROR Printer::CleanPen()
1031 DBG1("Printer::ClearPen() called\n");
1033 DWORD length=sizeof(PEN_CLEAN_PML);
1034 return pSS->ToDevice(PEN_CLEAN_PML,&length);
1038 PrintMode* Printer::GetMode
1043 if (index >= ModeCount)
1048 return pMode[index];
1052 PrintMode::PrintMode
1058 pmQuality = QUALITY_NORMAL;
1059 pmMediaType = MEDIA_PLAIN;
1067 BaseResX = BaseResY = TextRes = 300;
1071 for (iCount = 0; iCount < MAXCOLORPLANES; iCount++)
1073 ResolutionX[iCount] = BaseResX;
1074 ResolutionY[iCount] = BaseResY;
1075 ColorDepth[iCount] = 1;
1078 medium = mediaPlain;
1079 theQuality = qualityNormal;
1082 Config.bResSynth = TRUE;
1084 #if defined(APDK_VIP_COLORFILTERING)
1085 Config.bErnie = FALSE;
1088 Config.bPixelReplicate = TRUE;
1089 Config.bColorImage = TRUE;
1090 Config.bCompress = TRUE;
1092 BlackFEDTable = GetHTBinary();
1093 ColorFEDTable = GetHTBinary();
1096 // set for most common cases
1097 bFontCapable = TRUE;
1098 CompatiblePens[0] = BOTH_PENS;
1099 for(iCount = 1; iCount < MAX_COMPATIBLE_PENS; iCount++)
1101 CompatiblePens[iCount] = DUMMY_PEN;
1104 #ifdef APDK_AUTODUPLEX
1105 bDuplexCapable = FALSE;
1106 DuplexMode = DUPLEXMODE_NONE;
1117 // grayscale uses econo, 300, 1 bit
1121 CompatiblePens[1] = BLACK_PEN; // accept either black or both
1126 CMYGrayMode::CMYGrayMode
1132 CompatiblePens[1] = COLOR_PEN; // accept either color or both
1138 KCMYGrayMode::KCMYGrayMode
1149 DRIVER_ERROR Printer::SetPenInfo
1159 // read the DevID into the stored strDevID
1160 err = pSS->GetDeviceID(pSS->strDevID, DevIDBuffSize, TRUE);
1163 // update the static values of the pens
1164 err = pSS->DR->ParseDevIDString((const char*)(pSS->strDevID),pSS->strModel,&(pSS->VIPVersion),pSS->strPens);
1167 if ((pStr = strstr((char*)pSS->strDevID,"VSTATUS:"))) // find the VSTATUS area
1171 else if ((pStr = strstr((char*)pSS->strDevID, ";S:00"))) // binary encoded device ID status (version 0)
1173 pStr += 19; // get to the number of pens field - 12 byte feature field
1175 else if ((pStr = strstr ((char *) pSS->strDevID, ";S:01")))
1177 pStr += 19; // same as version 00
1179 else if ((pStr = strstr((char*)pSS->strDevID, ";S:02"))) // binary encoded device ID status (version 2)
1181 // pStr += 21; // get to the number of pens field - 14 byte feature field
1182 pStr += 19; // same as version 00 - see registry.cpp
1184 else if ((pStr = strstr((char*)pSS->strDevID, ";S:03"))) // binary encoded device ID status (version 3)
1186 pStr += 21; // get to the number of pens field - 14 byte feature field
1188 else if ((pStr = strstr((char*)pSS->strDevID, ";S:04"))) // binary encoded device ID status (version 3)
1190 pStr += 25; // get to the number of pens field - 18 byte feature field
1192 else if ((pSS->GetVIPVersion ()) > 5)
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
1205 pStr = pSS->strPens;
1211 BOOL PrintMode::Compatible
1217 for (int i=0; i < MAX_COMPATIBLE_PENS; i++)
1219 if (CompatiblePens[i] == pens)
1229 DRIVER_ERROR Printer::SetPens
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)
1245 return UNSUPPORTED_PEN;
1249 void PrintMode::GetValues
1251 QUALITY_MODE& eQuality,
1257 if (&eQuality != NULL)
1259 eQuality = pmQuality;
1262 if (&eMedia != NULL)
1264 eMedia = pmMediaType;
1267 if (&eColor != NULL)
1272 if (&bDeviceText != NULL)
1274 bDeviceText = bFontCapable;
1279 void Printer::SetPMIndices()
1281 for (unsigned int i=0; i < ModeCount; i++)
1283 pMode[i]->myIndex = i;