1 /*****************************************************************************\
2 printer.cpp : Implimentation for the Printer class
3
4 Copyright (c) 1996 - 2015, HP 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 HP 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
Printer(SystemServices * pSys,int numfonts,BOOL proto)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
~Printer()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 ////////////////////////////////////////////////////////////////////////////
CreateCompressor(unsigned int RasterSize)195 Compressor* Printer::CreateCompressor (unsigned int RasterSize)
196 {
197 return new Mode9 (pSS, RasterSize); // most printers use mode 9
198 }
199
200 ////////////////////////////////////////////////////////////////////////////
CreateBlackPlaneCompressor(unsigned int RasterSize,BOOL bVIPPrinter)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
Flush(int FlushSize)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
ParseError(BYTE status_reg)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
Encapsulate(const RASTERDATA * InputRaster,BOOL bLastPlane)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
Send(const BYTE * pWriteBuff)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
Send(const BYTE * pWriteBuff,DWORD dwWriteCount)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) &&
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;
692 if (IOMode.bStatus)
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
TopCoverOpen(BYTE)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
CleanPen()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
GetMode(unsigned int index)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
PrintMode(uint32_t * map1,uint32_t * map2)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
GrayMode(uint32_t * map)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
CMYGrayMode(uint32_t * map)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
KCMYGrayMode(uint32_t * map)1138 KCMYGrayMode::KCMYGrayMode
1139 (
1140 uint32_t *map
1141 ) :
1142 GrayMode(map)
1143 {
1144 dyeCount = 4;
1145 pmColor = GREY_CMY;
1146 } //KCMYGrayMode
1147
1148
SetPenInfo(char * & pStr,BOOL QueryPrinter)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
Compatible(PEN_TYPE pens)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
SetPens(PEN_TYPE eNewPen)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
GetValues(QUALITY_MODE & eQuality,MEDIATYPE & eMedia,COLORMODE & eColor,BOOL & bDeviceText)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
SetPMIndices()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
1290