Tizen 2.1 base
[platform/upstream/hplip.git] / prnt / hpijs / dj9xxvip.cpp
1 /*****************************************************************************\
2   dj9xxvip.cpp : Implimentation for the DJ9xxVIP class
3
4   Copyright (c) 1996 - 2002, 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 #ifdef APDK_DJ9xxVIP
33
34 #include "header.h"
35 #include "io_defs.h"
36 #include "dj9xxvip.h"
37 #include "printerproxy.h"
38
39 APDK_BEGIN_NAMESPACE
40
41
42 #define OUR_PJL_JOBNAME "_PJL_pjl_PJL_pjl_" // this can be anything we want it to be
43 #define DRIVERWARE_JOBNAME  "NEWDRIVERWARE" // don't change this - it is defined in firmware!
44
45 extern uint32_t ulMapDJ600_CCM_K[ 9 * 9 * 9 ];
46
47 const char GrayscaleSeq[]= {ESC, '*', 'o', '5', 'W', 0x0B, 0x01, 0x00, 0x00, 0x02};\r
48 \r
49 const BYTE ExtraDryTime[] = "\033&b16WPML \004\000\006\001\004\001\004\001\006\010\001";\r
50
51 extern BYTE EscAmplCopy(BYTE *dest, int num, char end);
52 extern void AsciiHexToBinary(BYTE* dest, char* src, int count);
53 extern MediaType MediaTypeToPcl (MEDIATYPE eMediaType);\r
54
55 DJ9xxVIP::DJ9xxVIP
56 (
57     SystemServices* pSS,
58     BOOL proto
59 ) :
60     Printer(pSS, NUM_DJ6XX_FONTS, proto),
61     PCL3acceptsDriverware(TRUE)
62 {
63
64     m_bVIPPrinter = TRUE;
65
66     if (!proto && IOMode.bDevID)
67     {
68         bCheckForCancelButton = TRUE;
69         constructor_error = VerifyPenInfo();
70         CERRCHECK;
71     }
72     else ePen = BOTH_PENS;    // matches default mode
73
74     PCL3acceptsDriverware = IsPCL3DriverwareAvailable();
75
76     ModeCount = 0;
77     pMode[ModeCount++] = new GrayModeDJ990(ulMapDJ600_CCM_K,PCL3acceptsDriverware);  // Grayscale K
78     pMode[ModeCount++] = new DJ990Mode();           // Automatic Color
79     pMode[ModeCount++] = new DJ990CMYGrayMode();    // Automatic Grayscale CMY
80
81 #ifdef APDK_AUTODUPLEX
82
83 /*
84  *  When bidi is available, query printer for duplexer
85  *  For now, this is available only on Linux which is unidi only.
86  */
87
88     bDuplexCapable = TRUE;
89 #endif 
90
91 #ifdef APDK_EXTENDED_MEDIASIZE
92     pMode[ModeCount++] = new DJ990KGrayMode ();        // Normal Grayscale K
93     pMode[ModeCount++] = new DJ9902400Mode ();         // HiRes
94     pMode[ModeCount++] = new DJ990DraftMode ();        // Draft Color
95 #endif
96     pMode[ModeCount++] = new DJ990BestMode ();         // Photo Best
97     pMode[ModeCount++] = new DJ990PhotoNormalMode ();  // Photo Normal
98 \r
99     m_cExtraDryTime    = 0;\r
100     m_iLeftOverspray   = 0;\r
101     m_iTopOverspray    = 0;\r
102     m_iRightOverspray  = 0;\r
103     m_iBottomOverspray = 0;
104 }
105
106 GrayModeDJ990::GrayModeDJ990
107 (
108     uint32_t *map,
109     BOOL PCL3OK
110 ) :
111     GrayMode(map)
112 {
113 #if defined(APDK_VIP_COLORFILTERING)
114     Config.bErnie = TRUE;
115 #endif
116
117     Config.bColorImage=FALSE;
118
119     if (!PCL3OK)
120     {
121         bFontCapable = FALSE;
122     }
123
124 #ifdef APDK_AUTODUPLEX
125     bDuplexCapable = TRUE;
126 #endif
127 #ifdef APDK_EXTENDED_MEDIASIZE
128     theQuality = qualityDraft;
129     pmQuality = QUALITY_DRAFT;
130 #endif
131 }
132
133 DJ990Mode::DJ990Mode()
134 : PrintMode(NULL)
135 {
136
137 /*
138  *  The resolutions here are set to 300 for better performance from Cameras.
139  *  REVISIT: Must provide a true 600 dpi printmode later.
140  *  12/21/01
141  *
142  *  For now have added APDK_HIGH_RES_MODES which sets VIP_BASE_RES to 600 in dj9xxvip.h
143  *  If APDK_HIGH_RES_MODES is not defined then VIP_BASE_RES is 300.
144  *  1/9/2002 - JLM
145  */
146
147     BaseResX = BaseResY = TextRes = ResolutionX[0] = ResolutionY[0] = VIP_BASE_RES;
148
149     medium = mediaAuto;     // enable media-detect
150
151 #if defined(APDK_VIP_COLORFILTERING)
152     Config.bErnie = TRUE;
153 #endif
154
155     Config.bColorImage = FALSE;
156
157 #ifdef APDK_AUTODUPLEX
158     bDuplexCapable = TRUE;
159 #endif
160 } //DJ990Mode
161
162
163 DJ990CMYGrayMode::DJ990CMYGrayMode()
164 : PrintMode(NULL)
165 {
166
167 /*
168  *  See comments above regarding 300/600 dpi change
169  */
170
171     BaseResX = BaseResY = TextRes = ResolutionX[0] = ResolutionY[0] = VIP_BASE_RES;
172
173     medium = mediaAuto;     // enable media-detect
174
175 #if defined(APDK_VIP_COLORFILTERING)
176     Config.bErnie = TRUE;
177 #endif
178
179     Config.bColorImage = FALSE;
180
181 #ifdef APDK_AUTODUPLEX
182     bDuplexCapable = TRUE;
183 #endif
184     pmColor = GREY_CMY;
185     bFontCapable = FALSE;
186 } //DJ990CMYGrayMode
187
188 #ifdef APDK_EXTENDED_MEDIASIZE
189 DJ990KGrayMode::DJ990KGrayMode () : PrintMode (NULL)
190 {
191
192 /*
193  *  See comments above regarding 300/600 dpi change.
194  */
195
196     BaseResX = BaseResY = ResolutionX[0] = ResolutionY[0] = VIP_BASE_RES;
197     medium = mediaPlain;
198 #if defined(APDK_VIP_COLORFILTERING)
199     Config.bErnie = TRUE;
200 #endif
201
202     Config.bColorImage = FALSE;
203
204 #ifdef APDK_AUTODUPLEX
205     bDuplexCapable = TRUE;
206 #endif
207     pmColor = GREY_K;
208     bFontCapable = FALSE;
209     dyeCount = 1;
210 } //DJ990KGrayMode
211
212 DJ9902400Mode::DJ9902400Mode () : PrintMode (NULL)
213 {
214     BaseResX =
215     BaseResY = 1200;
216     ResolutionX[0] = 1200;
217     ResolutionY[0] = 1200;
218     bFontCapable = FALSE;
219 #ifdef APDK_AUTODUPLEX
220     bDuplexCapable = FALSE;
221 #endif
222 #if defined(APDK_VIP_COLORFILTERING)
223     Config.bErnie = TRUE;
224 #endif
225
226     Config.bColorImage = FALSE;
227
228     medium = mediaHighresPhoto;
229     theQuality = qualityPresentation;
230     pmMediaType = MEDIA_PHOTO;
231     pmQuality = QUALITY_HIGHRES_PHOTO;
232 } // DJ9902400Mode
233
234 DJ990DraftMode::DJ990DraftMode () : PrintMode (NULL)
235 {
236     bFontCapable = FALSE;
237 #ifdef APDK_AUTODUPLEX
238     bDuplexCapable = TRUE;
239 #endif
240 #if defined(APDK_VIP_COLORFILTERING)
241     Config.bErnie = TRUE;
242 #endif
243
244    Config.bColorImage = FALSE;
245
246     medium = mediaAuto;
247     theQuality = qualityDraft;
248     pmQuality = QUALITY_DRAFT;
249 } // DJ990DraftMode
250
251 #endif  // APDK_EXTENDED_MEDIASIZE
252
253 /*
254  *  Some VIP printers do not have Media Sensing device. To enable
255  *  selection of Photo/Best mode for these printers, use this mode.
256  */
257
258 DJ990BestMode::DJ990BestMode () : PrintMode (NULL)
259 {
260     BaseResX = BaseResY = ResolutionX[0] = ResolutionY[0] = VIP_BASE_RES;
261
262         bFontCapable = FALSE;
263
264 #ifdef  APDK_AUTODUPLEX
265         bDuplexCapable = TRUE;
266 #endif
267
268 #if defined(APDK_VIP_COLORFILTERING)
269     Config.bErnie = TRUE;
270 #endif
271
272    Config.bColorImage = FALSE;
273
274         medium      = mediaGlossy;
275         theQuality  = qualityPresentation;
276         pmQuality   = QUALITY_BEST;
277     pmMediaType = MEDIA_PHOTO;
278 } // DJ990BestMode
279
280 DJ990PhotoNormalMode::DJ990PhotoNormalMode () : PrintMode (NULL)
281 {
282     BaseResX = BaseResY = ResolutionX[0] = ResolutionY[0] = VIP_BASE_RES;
283
284         bFontCapable = FALSE;
285
286 #ifdef  APDK_AUTODUPLEX
287         bDuplexCapable = TRUE;
288 #endif
289
290 #if defined(APDK_VIP_COLORFILTERING)
291     Config.bErnie = TRUE;
292 #endif
293
294    Config.bColorImage = FALSE;
295
296         medium      = mediaGlossy;
297         theQuality  = qualityNormal;
298         pmQuality   = QUALITY_NORMAL;
299     pmMediaType = MEDIA_PHOTO;
300 } // DJ990PhotoNormalMode
301
302 BOOL DJ9xxVIP::UseGUIMode
303 (
304     PrintMode* pPrintMode
305 )
306 {
307         // The reason to change all print mode in DJ9xxVIP family to PCL3GUI mode is that 
308         // the PCL3 path in VIP printers is not tested.  They don't support newer CRD 
309         // command.  The device fint support for this group is not recommended.
310
311         return TRUE;
312         /*
313         if (pPrintMode->medium == mediaHighresPhoto)
314         {
315                 return TRUE;
316         }
317         else
318         {
319 #ifdef APDK_AUTODUPLEX
320                 if (pPrintMode->QueryDuplexMode() != DUPLEXMODE_NONE)
321                 {
322                         return TRUE;
323                 }
324 #endif
325         }
326 #if defined(APDK_FONTS_NEEDED)
327 //    return ((!pPrintMode->bFontCapable) && (!PCL3acceptsDriverware));
328     return (!pPrintMode->bFontCapable);
329 #else
330     return TRUE;
331 #endif
332         */ 
333 } //UseGUIMode
334
335 DRIVER_ERROR DJ9xxVIP::AddPJLHeader ()\r
336 {\r
337     char            *szPJLBuffer = NULL;\r
338     DRIVER_ERROR    err = NO_ERROR;\r
339     int             iPJLBufferSize;\r
340     if (((iPJLBufferSize = pSS->GetPJLHeaderBuffer (&szPJLBuffer)) > 0) && (szPJLBuffer != NULL))\r
341     {\r
342         err = Send ((const BYTE *) szPJLBuffer, iPJLBufferSize);\r
343     }\r
344     return err;\r
345 }\r
346
347 Mode10::Mode10
348 (
349     SystemServices* pSys,
350     Printer* pPrinter,
351     unsigned int PlaneSize
352 ) :
353     Compressor(pSys, PlaneSize, TRUE),
354     thePrinter(pPrinter)    // needed by Flush
355 {
356     if (constructor_error != NO_ERROR)  // if error in base constructor
357     {
358         return;
359     }
360
361         // In the worst case, compression expands data by 50%
362         compressBuf = (BYTE*)pSS->AllocMem(PlaneSize + PlaneSize/2);
363         if (compressBuf == NULL)
364                 constructor_error=ALLOCMEM_ERROR;
365
366     memset(SeedRow,0xFF,PlaneSize);
367 } //Mode10
368
369
370 Mode10::~Mode10()
371 { }
372
373
374 const BYTE ResetSeedrow[]={ESC,'*','b','0','Y'};
375
376 void Mode10::Flush()
377 // special problem here regarding white rasters: we can't just reset our seedrow to white,
378 // because if a true white raster comes next it will compress to zero, and firmware will
379 // print ITS seedrow. So when we zero our seedrow, we need to zero the firmware seedrow.
380 // The way to do this is to send ESC*b0Y. So that's what we will do here.
381 {
382     if (!seeded)
383     {
384         return;
385     }
386         compressedsize=0;
387         
388     iRastersReady = 0;
389     seeded = FALSE;
390     memset(SeedRow,0xFF,inputsize);
391     thePrinter->Send(ResetSeedrow, sizeof(ResetSeedrow));
392 } //Flush
393
394
395 Compressor* DJ9xxVIP::CreateCompressor(unsigned int RasterSize)
396 {
397     return new Mode10(pSS,this,RasterSize);
398 }
399
400
401 Header* DJ9xxVIP::SelectHeader(PrintContext* pc)
402 {
403     return new HeaderDJ990(this,pc);
404 }
405
406
407 HeaderDJ990::HeaderDJ990(Printer* p,PrintContext* pc)
408     : Header(p,pc)
409 {
410     SetMediaSource (pc->GetMediaSource());
411 }
412
413
414 DRIVER_ERROR HeaderDJ990::ConfigureRasterData()
415 // This is the more sophisticated way of setting color and resolution info.
416 //
417 // NOTE: Will need to be overridden for DJ5xx.
418 {
419
420         char buff[50];      // 20 + 3 for crdstart + 3 for ##W
421         char *out = buff;
422
423
424     // begin the CRD command
425     memcpy(out,crdStart,sizeof(crdStart) );
426     out += sizeof(crdStart);
427
428     // now set up the "#W" part, where #= number of data bytes in the command
429     // #= 20
430     //      format,ID,components(2bytes),resolutions (4bytes),
431     //      compresssion method, orientation, bits/component,planes/component
432         *out++ = 0x32;    // "2"
433     *out++ = 0x30;    // "0"
434     *out++ = 'W';
435
436 #define VIPcrdFormat 6
437 #define VIPKRGBID 0x1F
438
439     *out++ = VIPcrdFormat;
440     *out++ = VIPKRGBID;
441
442     // 2-byte component count field
443     // number of components for sRGB is 1 by defintiion
444     *out++ = 0;     // leading byte
445     *out++ = 2;     // 2 "component"
446
447     *out++ = ResolutionX[0]/256;
448     *out++ = ResolutionX[0]%256;
449     *out++ = ResolutionY[0]/256;
450     *out++ = ResolutionY[0]%256;
451
452     // compression method
453     *out++ = 9;    // mode 9 compression
454
455     // orientation
456     *out++ = 0;     // pixel major code
457
458     // bits per component
459     *out++ = 1;    // 1 bits each for k
460
461     // planes per component
462     *out++ = 1;     // K = one component, one "plane"
463
464     *out++ = ResolutionX[0]/256;
465     *out++ = ResolutionX[0]%256;
466     *out++ = ResolutionY[0]/256;
467     *out++ = ResolutionY[0]%256;
468
469     // compression method
470     *out++ = 10;    // mode 10 compression
471
472     // orientation
473     *out++ = 1;     // pixel major code
474
475     // bits per component
476     *out++ = 32;    // 8 bits each for s,R,G,B
477
478     // planes per component
479     *out++ = 1;     // sRGB = one component, one "plane"
480
481     return thePrinter->Send((const BYTE*) buff, out-buff);
482 } //ConfigureRasterData
483
484
485 DRIVER_ERROR HeaderDJ990::ConfigureImageData()
486 {
487     DRIVER_ERROR err = thePrinter->Send((const BYTE*)cidStart, sizeof(cidStart));
488     ERRCHECK;
489     char sizer[3];
490     sprintf(sizer,"%dW",6);
491     err = thePrinter->Send((const BYTE*)sizer,2);
492     ERRCHECK;
493
494     BYTE colorspace = 2;    // RGB
495     BYTE coding = 3;
496     BYTE bitsindex = 3;     // ??
497     BYTE bitsprimary = 8;
498     BYTE CID[6];
499     CID[0] = colorspace;
500     CID[1]=coding;
501     CID[2] = bitsindex;
502     CID[3] = CID[4] = CID[5] = bitsprimary;
503
504     return thePrinter->Send((const BYTE*) CID, 6);
505 } //ConfigureImageData
506
507
508 DRIVER_ERROR HeaderDJ990::Send()
509 /// ASSUMES COMPRESSION ALWAYS ON -- required by DJ990
510 {
511     DRIVER_ERROR err;
512 //    PRINTMODE_VALUES    *pPMV;
513     COLORMODE       eColorMode = COLOR;
514     MEDIATYPE       eMediaType;
515     QUALITY_MODE    eQualityMode;
516     BOOL            bDeviceText;
517
518     thePrintContext->GetPrintModeSettings (eQualityMode, eMediaType, eColorMode, bDeviceText);\r
519
520     if (eMediaType == MEDIA_CDDVD)
521     {
522         thePrintContext->SetMediaSource (sourceTrayCDDVD);
523         SetMediaSource (sourceTrayCDDVD);
524     }
525 \r
526     StartSend();
527
528 #ifdef APDK_AUTODUPLEX
529     if (thePrintContext->QueryDuplexMode () != DUPLEXMODE_NONE)
530     {
531         err = thePrinter->Send ((const BYTE *) EnableDuplex, sizeof (EnableDuplex));\r
532         BYTE    cDryTime;\r
533         cDryTime = (BYTE) ((thePrinter->GetHint (EXTRA_DRYTIME_HINT)) & 0xFF);\r
534         if (cDryTime != 0)\r
535         {\r
536             err = thePrinter->Send (ExtraDryTime, sizeof (ExtraDryTime) - 1);\r
537             err = thePrinter->Send ((const BYTE *) &cDryTime, 1);\r
538             ERRCHECK;\r
539         }
540     }
541 #endif
542
543     err = ConfigureImageData();
544     ERRCHECK;
545
546     err = ConfigureRasterData();
547     ERRCHECK;
548
549     if (thePrintMode->dyeCount == 1)    // grayscale
550     {
551         err=thePrinter->Send((const BYTE*)GrayscaleSeq, sizeof(GrayscaleSeq) );
552         ERRCHECK;
553     }
554     else
555     {
556         if (eColorMode == GREY_CMY)
557         {
558             char    pStr[12];
559             memcpy (pStr, GrayscaleSeq, 10);
560             pStr[9] = 0x01;
561             err = thePrinter->Send ((const BYTE *) pStr, 10);
562         }
563     }
564
565     /////////////////////////////////////////////////////////////////////////////////////
566     // unit-of-measure command --- seems to be need in DJ990 PCL3 mode
567     char uom[10];
568     sprintf(uom,"%c%c%c%d%c",ESC,'&','u',thePrintMode->ResolutionX[K],'D');
569     err = thePrinter->Send((const BYTE*)uom, strlen (uom));
570     ERRCHECK;
571
572     // another command that helps PCLviewer
573     unsigned int width=thePrintContext->OutputPixelsPerRow();
574     unsigned int digits = 1;
575     unsigned int x = width;
576     while (x > 10)
577     {
578         digits++;
579         x = x / 10;
580     }
581     sprintf(uom,"%c%c%c%d%c",ESC,'*','r', width,'S');
582     err = thePrinter->Send((const BYTE*)uom, 4 + digits );
583     ERRCHECK;
584
585     ////////////////////////////////////////////////////////////////////////////////////
586
587 /*
588  *  Custom papersize command
589  */
590
591     if (thePrintContext->thePaperSize == CUSTOM_SIZE)
592     {
593         BYTE    szStr[32];
594         short   sWidth, sHeight;
595         BYTE    b1, b2;
596         sWidth  = (short) (thePrintContext->PhysicalPageSizeX () * thePrintContext->EffectiveResolutionX ());
597         sHeight = (short) (thePrintContext->PhysicalPageSizeY () * thePrintContext->EffectiveResolutionY ());
598         memcpy (szStr, "\x1B*o5W\x0E\x05\x00\x00\x00\x1B*o5W\x0E\x06\x00\x00\x00", 20);
599         b1 = (BYTE) ((sWidth & 0xFF00) >> 8);
600         b2 = (BYTE) (sWidth & 0xFF);
601         szStr[8] = b1;
602         szStr[9] = b2;
603         b1 = (BYTE) ((sHeight & 0xFF00) >> 8);
604         b2 = (BYTE) (sHeight & 0xFF);
605         szStr[18] = b1;
606         szStr[19] = b2;
607         err = thePrinter->Send ((const BYTE *) szStr, 20);
608     }
609
610     float   fXOverSpray = 0.0;
611     float   fYOverSpray = 0.0;
612     float   fLeftOverSpray = 0.0;
613     float   fTopOverSpray  = 0.0;
614         FullbleedType   fbType;
615     if (thePrintContext->bDoFullBleed &&
616         thePrinter->FullBleedCapable (thePrintContext->thePaperSize,
617                                                                           &fbType,
618                                       &fXOverSpray, &fYOverSpray,
619                                       &fLeftOverSpray, &fTopOverSpray))
620     {
621
622 /*
623  *      To get the printer to do fullbleed printing, send the top and
624  *      left overspray commands. Overspray is needed to take care of
625  *      skew during paper pick. These values may be mech dependent.
626  *      Currently, supported only on PhotoSmart 100. Malibu supports
627  *      fullbleed printing also. The current values for overspray are
628  *      0.059 inch for top, bottom and left edges and 0.079 for right edge.
629  */
630
631         BYTE cBuf[4];
632         BYTE TopOverSpraySeq[]  = {0x1b, 0x2A, 0x6F, 0x35, 0x57, 0x0E, 0x02, 0x00};
633                                 // "Esc*o5W 0E 02 00 00 00" Top edge overspray for full-bleed printing
634
635         BYTE LeftOverSpraySeq[] = {0x1b, 0x2A, 0x6F, 0x35, 0x57, 0x0E, 0x01, 0x00};
636                                 // "Esc*o5W 0E 01 00 00 00" Left edge overspray for full-bleed printing
637
638         short topspray = (short)(fTopOverSpray * thePrintContext->EffectiveResolutionY() + 0.5);
639         cBuf[1] = topspray & 0xFF;
640         cBuf[0] = topspray >> 8;
641
642         err = thePrinter->Send ((const BYTE *) TopOverSpraySeq, sizeof (TopOverSpraySeq));
643         err = thePrinter->Send ((const BYTE *) cBuf, 2);
644
645         // set the left overspray value based on resolution and global constant for horizontal overspray
646         short leftspray = (short)(fLeftOverSpray * thePrintContext->EffectiveResolutionX() + 0.5);
647         cBuf[1] = leftspray & 0xFF;
648         cBuf[0] = leftspray >> 8;
649
650         err = thePrinter->Send ((const BYTE *) LeftOverSpraySeq, sizeof (LeftOverSpraySeq));
651         err = thePrinter->Send ((const BYTE *) cBuf, 2);
652     }
653
654 //  Now send media pre-load command
655     err = thePrinter->Send ((const BYTE *) "\033&l-2H", 6);   // Moved from Modes(), des 3/11/03
656     ERRCHECK;
657 \r
658 //  Send speed mech command\r
659     thePrinter->SetHint (SPEED_MECH_HINT, 0);\r
660
661     // no need for compression command, it's in the CRD
662
663     err = thePrinter->Send((const BYTE*)grafStart, sizeof(grafStart) );
664     ERRCHECK;
665
666     if (!thePrinter->UseGUIMode (thePrintContext->CurrentMode) &&
667         (thePrintContext->PhysicalPageSizeX ()) < 8.0)
668     {
669
670         BYTE    blankRow[40];
671         memset (blankRow, 0xFF, 40);
672         strcpy ((char *) blankRow, "\033*p0Y\033*b23W");
673         blankRow[11] = 18;   // ce, 7f
674         blankRow[30] = 0xCE; blankRow[31] = 0x7F;
675         err = thePrinter->Send ((const BYTE *) blankRow, 34);
676     }
677
678     return err;
679 } //Send
680
681
682 DRIVER_ERROR HeaderDJ990::StartSend()
683 {
684     DRIVER_ERROR err;
685
686     err = thePrinter->Send((const BYTE*)Reset,sizeof(Reset));
687     ERRCHECK;
688
689     err = thePrinter->Send((const BYTE*)UEL,sizeof(UEL));
690     ERRCHECK;
691 \r
692     err = thePrinter->AddPJLHeader ();\r
693     ERRCHECK;\r
694 \r
695     err = thePrinter->Send((const BYTE*)EnterLanguage,sizeof(EnterLanguage));
696     ERRCHECK;
697
698     if (!thePrinter->UseGUIMode(thePrintContext->CurrentMode))
699     {
700         err = thePrinter->Send((const BYTE*)PCL3,sizeof(PCL3));
701     }
702     else
703     {
704         err = thePrinter->Send((const BYTE*)PCLGUI,sizeof(PCLGUI));
705     }
706     ERRCHECK;
707
708
709     err = thePrinter->Send((const BYTE*)&LF,1);
710     ERRCHECK;
711
712     err = Modes ();            // Set media source, type, size and quality modes.
713     ERRCHECK;
714 \r
715 //  Send media subtype if set\r
716     int    iMediaSubtype = thePrintContext->GetMediaSubtype ();\r
717     if (iMediaSubtype != APDK_INVALID_VALUE)\r
718     {\r
719         BYTE    szMediaSubtypeSeq[] = {0x1B, '*', 'o', '5', 'W', 0x0D, 0x03, 0x00, 0x00, 0x00};\r
720         szMediaSubtypeSeq[8] = (BYTE) ((iMediaSubtype & 0xFF00) >> 8);\r
721         szMediaSubtypeSeq[9] = (BYTE) (iMediaSubtype & 0x00FF);\r
722         err = thePrinter->Send ((const BYTE *) szMediaSubtypeSeq, sizeof(szMediaSubtypeSeq));\r
723         ERRCHECK;\r
724     }\r
725
726     if (!thePrinter->UseGUIMode(thePrintContext->CurrentMode))
727     {
728         err = Margins();          // set margins
729     }
730
731 // special GUI mode top margin set
732
733     else if ((thePrintContext->PrintableStartY ()) > 0.0)
734     {
735         CAPy = thePrintContext->GUITopMargin();
736     }
737
738     if ((thePrintContext->GetMediaSource()) == sourceTrayCDDVD)
739     {
740         err = thePrinter->Send ((const BYTE *) "\033*o5W\x0D\x03\x00\x04\x0C", 10);
741         ERRCHECK;
742     }
743
744     return err;
745 } //StartSend
746
747 /* This could replace Header::SetMediaSource in header.cpp. des 8/5/02 */
748 void HeaderDJ990::SetMediaSource(MediaSource msource)
749 // Sets value of PCL::mediasource and associated counter msrccount
750 {
751     msrccount=EscAmplCopy((BYTE*)mediasource,msource,'H');
752     if (msource == sourceTrayCDDVD)
753     {
754         SetMediaType (mediaCDDVD);
755         SetQuality (qualityPresentation);
756         return;
757     }
758     if (msource == sourceTray2 || msource > sourceTrayAuto)
759     {
760         SetMediaType (mediaPlain);
761     }
762 }
763
764 DRIVER_ERROR DJ9xxVIP::VerifyPenInfo()
765 {
766     DRIVER_ERROR err=NO_ERROR;
767
768     if(IOMode.bDevID == FALSE)
769         return err;
770     err = ParsePenInfo(ePen);
771
772     if(err == UNSUPPORTED_PEN) // probably Power Off - pens couldn't be read
773     {
774         DBG1("DJ9xxVIP::Need to do a POWER ON to get penIDs\n");
775
776         // have to delay or the POWER ON will be ignored
777         if (pSS->BusyWait((DWORD)2000) == JOB_CANCELED)
778         {
779             return JOB_CANCELED;
780         }
781
782         DWORD length = sizeof(DJ895_Power_On);
783         err = pSS->ToDevice(DJ895_Power_On,&length);
784         ERRCHECK;
785
786         err = pSS->FlushIO();
787         ERRCHECK;
788
789         // give the printer some time to power up
790         if (pSS->BusyWait ((DWORD) 2500) == JOB_CANCELED)
791         {
792             return JOB_CANCELED;
793         }
794
795         err = ParsePenInfo(ePen);
796     }
797
798     ERRCHECK;
799
800     // check for the normal case
801     if (ePen == BOTH_PENS || ePen == MDL_BLACK_AND_COLOR_PENS)
802     {
803         return NO_ERROR;
804     }
805
806 //  Should we return NO_ERROR for MDL_BOTH also - malibu??
807
808     while ( ePen != BOTH_PENS &&  pSS->GetVIPVersion () == 1  )
809     {
810
811         switch (ePen)
812         {
813             case BLACK_PEN:
814                 // black pen installed, need to install color pen
815                 pSS->DisplayPrinterStatus(DISPLAY_NO_COLOR_PEN);
816                 break;
817             case COLOR_PEN:
818                 // color pen installed, need to install black pen
819                 pSS->DisplayPrinterStatus(DISPLAY_NO_BLACK_PEN);
820                 break;
821             case NO_PEN:
822                 // neither pen installed
823             default:
824                 pSS->DisplayPrinterStatus(DISPLAY_NO_PENS);
825                 break;
826         }
827
828         if (pSS->BusyWait(500) == JOB_CANCELED)
829         {
830             return JOB_CANCELED;
831         }
832
833         err =  ParsePenInfo(ePen);
834         ERRCHECK;
835     }
836
837     pSS->DisplayPrinterStatus(DISPLAY_PRINTING);
838
839     return NO_ERROR;
840 } //VerifyPenInfo
841
842
843 DRIVER_ERROR DJ9xxVIP::ParsePenInfo(PEN_TYPE& ePen, BOOL QueryPrinter)
844 {
845     char* str;
846     int num_pens = 0;
847     PEN_TYPE temp_pen1 = NO_PEN;
848     BYTE penInfoBits[4];
849     int     i;
850
851 /*
852  *  First check if this printer's firmware version is one I know about. Currently
853  *  I know upto S:04. I can't guess if the pen info nibbles have shifted in the
854  *  new version. Can't tell the user about missing pens.
855  */
856
857     if ((pSS->GetVIPVersion ()) > 5)
858     {
859         ePen = BOTH_PENS;
860         return NO_ERROR;
861     }
862
863     DRIVER_ERROR err = SetPenInfo (str, QueryPrinter);
864 //    ERRCHECK;
865     if (err != NO_ERROR)
866     {
867         ePen = BOTH_PENS;
868         return NO_ERROR;
869     }
870     iNumMissingPens = 0;
871
872     // the first byte indicates how many pens are supported
873     if ((str[0] >= '0') && (str[0] <= '9'))
874     {
875         num_pens = str[0] - '0';
876     }
877     else if ((str[0] >= 'A') && (str[0] <= 'F'))
878     {
879         num_pens = 10 + (str[0] - 'A');
880     }
881     else if ((str[0] >= 'a') && (str[0] <= 'f'))
882     {
883         num_pens = 10 + (str[0] - 'a');
884     }
885     else
886     {
887         return BAD_DEVICE_ID;
888     }
889
890     if ((int) strlen (str) < (num_pens * 8))
891     {
892         return BAD_DEVICE_ID;
893     }
894
895 //  DJ990 style DevID
896
897     if (pSS->GetVIPVersion () == 1)
898     {
899         if (num_pens < 2)
900         {
901             return UNSUPPORTED_PEN;
902         }
903
904         // parse pen1 (should be black)
905         AsciiHexToBinary(penInfoBits, str+1, 4);
906         penInfoBits[1] &= 0xf8; // mask off ink level trigger bits
907
908         if ((penInfoBits[0] == 0xc1) && (penInfoBits[1] == 0x10))
909         {
910             temp_pen1 = BLACK_PEN;
911         }
912         else if (penInfoBits[0] == 0xc0)
913         {   // missing pen
914             temp_pen1 = NO_PEN;
915             iNumMissingPens = 1;
916         }
917         else
918         {
919             return UNSUPPORTED_PEN;
920         }
921
922         // now check pen2 (should be color)
923         AsciiHexToBinary(penInfoBits, str+9, 4);
924         penInfoBits[1] &= 0xf8; // mask off ink level trigger bits
925
926         if ((penInfoBits[0] == 0xc2) && (penInfoBits[1] == 0x08))
927         {   // Chinook
928             if (temp_pen1 == BLACK_PEN)
929             {
930                 ePen = BOTH_PENS;
931             }
932             else
933             {
934                 ePen = COLOR_PEN;
935             }
936         }
937         else if (penInfoBits[0] == 0xc0)
938         {   // missing pen
939             ePen = temp_pen1;
940             iNumMissingPens = 1;
941         }
942         else
943         {
944             return UNSUPPORTED_PEN;
945         }
946
947         return NO_ERROR;
948     }
949
950 //  Check for missing pens
951
952     if (*(str - 1) == '1' && *(str - 2) == '1')
953     {
954         return UNSUPPORTED_PEN;
955     }
956
957     char    *p = str + 1;
958
959 /*
960  *  Pen Type Info
961  *
962     Bit 31 (1 bit)
963
964     1 if these fields describe a print head
965     0 otherwise
966     Bit 30 (1 bit)
967
968     1 if these fields describe an ink supply
969     0 otherwise
970
971     Bits 29 .. 24 (6 bits) describes the pen/supply type:
972
973     0  = none
974     1  = black
975     2  = CMY
976     3  = KCM
977     4  = Cyan
978     5  = Meganta
979     6  = Yellow
980         7  = Cyan - low dye load 
981     8  = Magenta - low dye load 
982     9  = Yellow - low dye load (may never be used, but reserve space anyway) [def added Jun 3, 2002]
983     10 = gGK - two shades of grey plus black; g=light grey, G=medium Grey, K=black  [added Sep 12, 02]
984     11 = Blue Pen
985     12 .. 62 = reserved for future use
986     63 = Unknown
987
988     Bits 23 .. 19 (5 bits) describes the pen/supply id:
989
990     0 = none
991     1 = color (Formerly N)
992     2 = black (Formerly H)
993     3 = Flash (Formerly F)
994     4 = (Formerly R -- only 6xx family)
995     5 = (Formerly C -- only 6xx family)
996     6 = (Formerly M -- only for 6xx family)
997     7 = (Cp1160 Pen)
998     8 = Europa (Jupiter Ink)
999     9 = Wax (pen/ink combo; k)  
1000     10 = (pen/ink combo; cmy)  
1001     11 = (pen/ink combo; kcm) 
1002     12 = (pen/ink combo; k)    [def added Jun 27, 2002]
1003     13 = (k)  [def added Jun 27, 2002]
1004     14 = pen/ink combo; gGK)  [added Sep 12, 02] 
1005     15 .. 30 = reserved for future use    [def added Jun 27, 2002]
1006     31 = Other/Unknown  [def added Jun 27, 2002]
1007  */
1008
1009     ePen = NO_PEN;
1010
1011     if (pSS->GetVIPVersion () == 3)
1012     {
1013         for (i = 0; i < num_pens; i++, p += 4)
1014         {
1015             if (*p > 0 && *p < '5')
1016             {
1017                 continue;
1018             }
1019             switch (*p)
1020             {
1021                 case 0:
1022                 {
1023                     iNumMissingPens++;
1024                     break;
1025                 }
1026                 case '5':
1027                 {
1028                     ePen = BLACK_PEN;
1029                     break;
1030                 }
1031                 case '6':
1032                 case '7':
1033                 case '8':
1034                 {
1035                     if (ePen == BLACK_PEN)
1036                     {
1037                         ePen = BOTH_PENS;
1038                     }
1039                     else if (ePen != BOTH_PENS)
1040                     {
1041                         ePen = COLOR_PEN;
1042                     }
1043                     break;
1044                 }
1045             }
1046
1047         }
1048         if (iNumMissingPens != 0)
1049         {
1050             return MISSING_PENS;
1051         }
1052         return NO_ERROR;
1053     }
1054
1055 #if 0
1056
1057     BYTE    penColor;
1058
1059 /*
1060  *  These printers don't need all pens to be installed to print. Parsing the pen info
1061  *  is not all that useful. Also, the note about incompatible pen is not valid anymore,
1062  *  it just means unknown or other pen.
1063  *  Raghu - 11/17/05
1064  */
1065
1066     for (i = 0; i < num_pens; i++, p += 8)
1067     {
1068         AsciiHexToBinary (penInfoBits, p, 8);
1069
1070         if ((penInfoBits[1] & 0xf8) == 0xf8)
1071         {
1072
1073 //          The high 5 bits in the 3rd and 4th nibble (second byte) identify the
1074 //          installed pen. If all 5 bits are on, user has installed an incompatible pen.
1075
1076             return UNSUPPORTED_PEN;
1077         }
1078
1079         if ((penInfoBits[0] & 0x40) != 0x40)         // if Bit 31 is 1, this is not a pen
1080         {
1081             continue;
1082         }
1083         penColor = penInfoBits[0] & 0x3F;
1084         switch (penColor)
1085         {
1086             case 0:
1087             {
1088                 iNumMissingPens++;
1089                 break;
1090             }
1091             case 1:
1092                 ePen = BLACK_PEN;
1093                 break;
1094             case 2:
1095             {
1096                 if (ePen == BLACK_PEN)
1097                 {
1098                     ePen = BOTH_PENS;
1099                 }
1100                 else if (ePen == MDL_PEN)
1101                 {
1102                     ePen = MDL_BOTH;
1103                 }
1104                 else if (ePen == GREY_PEN)
1105                 {
1106                     ePen = GREY_BOTH;
1107                 }
1108                 else
1109                 {
1110                     ePen = COLOR_PEN;
1111                 }
1112                 break;
1113             }
1114             case 3:
1115                 if (ePen == BLACK_PEN)
1116                 {
1117                     ePen = MDL_AND_BLACK_PENS;
1118                 }
1119                 else if (ePen == COLOR_PEN)
1120                 {
1121                     ePen = MDL_BOTH;
1122                 }
1123                 else if (ePen == BOTH_PENS)
1124                 {
1125                     ePen = MDL_BLACK_AND_COLOR_PENS;
1126                 }
1127                 else if (ePen == GREY_PEN)
1128                 {
1129                     ePen = MDL_AND_GREY_PENS;
1130                 }
1131                 else if (ePen == GREY_BOTH)
1132                 {
1133                     ePen = MDL_GREY_AND_COLOR_PENS;
1134                 }
1135                 else
1136                 {
1137                     ePen = MDL_PEN;
1138                 }
1139                 break;
1140             case 4:             // cyan pen
1141             case 5:             // magenta pen
1142             case 6:             // yellow pen
1143             case 7:             // low dye load cyan pen
1144             case 8:             // low dye load magenta pen
1145             case 9:             // low dye load yellow pen
1146             case 11:            // blue pen
1147                 if (ePen == BLACK_PEN || ePen == BOTH_PENS)
1148                 {
1149                     ePen = BOTH_PENS;
1150                 }
1151                 else
1152                 {
1153                     ePen = COLOR_PEN;
1154                 }
1155                 break;
1156             case 10:
1157                 ePen = GREY_PEN;
1158                 break;
1159             default:
1160                 ePen = UNKNOWN_PEN;
1161         }
1162     }
1163     return NO_ERROR;
1164 #endif
1165
1166     ePen = BOTH_PENS;
1167     return NO_ERROR;
1168
1169 } //ParsePenInfo
1170
1171
1172 BOOL DJ9xxVIP::IsPCL3DriverwareAvailable()
1173 {
1174 #ifdef  APDK_LINUX
1175     // Linux supports Bi-Di, but is not enabled at this time. See comments below.
1176     return TRUE;
1177 #else
1178
1179     BOOL pcl3driverware = TRUE;     // default to TRUE since this is the case for all but some early units
1180     BOOL inAJob = FALSE;
1181     char *pStr;
1182     char *pEnd;
1183     BYTE devIDBuff[DevIDBuffSize];
1184     int maxWaitTries;
1185     int i;
1186
1187     // if don't have bidi can't check so assume driverware is ok since only certain
1188     // 990s don't handle driverware in PCL3 mode
1189     if (!IOMode.bDevID)
1190     {
1191         return TRUE;
1192     }
1193
1194     if (pSS->GetDeviceID(devIDBuff, DevIDBuffSize, TRUE) != NO_ERROR)
1195     {
1196         goto cleanup;
1197     }
1198
1199     // if printer does not have firmware based on the first 990 release
1200     // don't bother checking, can assume driverware commands are OK
1201     if (!strstr((const char*)devIDBuff+2,"MDL:DESKJET 990C") &&
1202         !strstr((const char*)devIDBuff+2,"MDL:PHOTOSMART 1215") &&
1203         !strstr((const char*)devIDBuff+2,"MDL:PHOTOSMART 1218") )
1204     {
1205         return TRUE;
1206     }
1207
1208     // high-level process to check if driverware is available in PCL3 mode:
1209     //  1. set JobName through the normal PJL command to some string X
1210     //  2. poll DeviceID until see this JobName (syncs host with printer in case
1211     //     printer is still printing an earlier job etc.)
1212     //  3. go into PCL3 mode
1213     //  4. send driverware command to set JobName
1214     //  5. get the DeviceID and look at the JobName, if it is not "NEWDRIVERWARE" (what
1215     //     the firmware driverware command sets it to) conclude that driverware is
1216     //     not available in PCL3 mode; if  the JobName is "NEWDRIVERWARE" then conclude
1217     //     that driverware is available in PCL3 mode
1218     //  6. exit this "job" (send a UEL)
1219
1220
1221
1222     // set the JobName via PJL
1223     if (Flush() != NO_ERROR) goto cleanup;
1224     if (Send((const BYTE*)UEL,sizeof(UEL)) != NO_ERROR) goto cleanup;
1225     inAJob = TRUE;
1226     if (Send((const BYTE*)JobName,sizeof(JobName)) != NO_ERROR) goto cleanup;
1227     if (Send((const BYTE*)&Quote,1) != NO_ERROR) goto cleanup;
1228     if (Send((const BYTE*)OUR_PJL_JOBNAME,strlen(OUR_PJL_JOBNAME)) != NO_ERROR) goto cleanup;
1229     if (Send((const BYTE*)&Quote,1) != NO_ERROR) goto cleanup;
1230     if (Send((const BYTE*)&LF,1) != NO_ERROR) goto cleanup;
1231     if (Flush() != NO_ERROR) goto cleanup;          // we flush our ::Send buffer
1232     if (pSS->FlushIO() != NO_ERROR) goto cleanup;   // we flush any external I/O buffer
1233
1234     // wait for printer to see this and set JobName in the DeviceID
1235     // we know printer will respond, it is just a matter of time so wait
1236     // a while until see it since it may take a few seconds
1237     // for it to sync up with us if it is busy printing or picking
1238     //
1239     // this is a pretty long timeout but if the printer is finishing up
1240     // a preceding job we need to give it time to finish it since it won't
1241     // set the new jobname until the last job is complete
1242     // one possible enhancement would be to look at the flags in the DeviceID
1243     // to see if a job is active on more than one i/o connection
1244     maxWaitTries = 120;  // wait max of 60sec
1245     for (i=0; i<maxWaitTries; i++)
1246     {
1247         if (pSS->GetDeviceID(devIDBuff, DevIDBuffSize, TRUE) != NO_ERROR)    goto cleanup;
1248         if ( (pStr=(char *)strstr((const char*)devIDBuff+2,";J:")) )
1249         {
1250             pStr += 3;
1251             if ( (pEnd=(char *)strstr((const char*)pStr,";")) )
1252             {
1253                 *pEnd = '\0';
1254                 while (pEnd > pStr) // take out trailing spaces in JobName before compare
1255                 {
1256                     if (*(pEnd-1) == ' ')
1257                     {
1258                         *(pEnd-1) = '\0';
1259                     }
1260                     else
1261                     {
1262                         break;
1263                     }
1264                     pEnd--;
1265                 }
1266                 if (!strcmp(pStr, OUR_PJL_JOBNAME))
1267                 {
1268                     break;
1269                 }
1270             }
1271             pSS->BusyWait((DWORD)500);
1272         }
1273         else
1274         {
1275             DBG1("JobName missing from DeviceID strings");
1276             goto cleanup;
1277         }
1278     }
1279     if (i>=maxWaitTries)
1280     {
1281         // printer didn't respond to driverware in PCL3GUI mode withing allowed timeout
1282         DBG1("Printer didn't respond to PJL\n");
1283         goto cleanup;
1284     }
1285
1286     // now printer is in sync with us so try PCL3 mode and expect it to react to command
1287     // immediately or will assume that it ignores driverware in that mode
1288     if (Send((const BYTE*)EnterLanguage,sizeof(EnterLanguage)) != NO_ERROR) goto cleanup;
1289     if (Send((const BYTE*)PCL3,sizeof(PCL3)) != NO_ERROR) goto cleanup;
1290     if (Send((const BYTE*)&LF,1) != NO_ERROR) goto cleanup;
1291     if (Send((const BYTE*)DriverwareJobName,sizeof(DriverwareJobName)) != NO_ERROR) goto cleanup;
1292     if (Flush() != NO_ERROR) goto cleanup;          // we flush our ::Send buffer
1293     if (pSS->FlushIO() != NO_ERROR) goto cleanup;   // we flush any external I/O buffer
1294
1295     // wait for printer to see this and set DeviceID to reflect this command
1296     // since we are sending in PCL3 mode we don't know if printer will respond
1297     // so don't wait very long
1298     maxWaitTries = 4;
1299     for (i=0; i<maxWaitTries; i++)
1300     {
1301         if (pSS->GetDeviceID(devIDBuff, DevIDBuffSize, TRUE) != NO_ERROR)    goto cleanup;
1302         if ( (pStr=(char *)strstr((const char*)devIDBuff+2,";J:")) )
1303         {
1304             pStr += 3;
1305             if ( (pEnd=(char *)strstr((const char*)pStr,";")) )
1306             {
1307                 *pEnd = '\0';
1308                 // firmware may have garbage in remainder of JobName buffer - truncate
1309                 // it to the length of the string that should be set before compare
1310                 if (!strncmp(pStr, DRIVERWARE_JOBNAME, strlen(DRIVERWARE_JOBNAME)))
1311                 {
1312                     pcl3driverware = TRUE;
1313                     break;
1314                 }
1315             }
1316             pSS->BusyWait((DWORD)500);
1317         }
1318         else
1319         {
1320             DBG1("JobName missing from DeviceID string");
1321             goto cleanup;
1322         }
1323     }
1324     if (i>=maxWaitTries)
1325     {
1326         // since we haven't gotten a response assume that the printer ignores driverware
1327         // commands in PCL3 mode
1328         pcl3driverware = FALSE;
1329     }
1330
1331
1332 cleanup:
1333     if (inAJob)   // send UEL in case left printer in the context of a job
1334     {
1335         if (Send((const BYTE*)UEL,sizeof(UEL)) != NO_ERROR) goto bailout;
1336         if (pSS->FlushIO() != NO_ERROR) goto bailout;
1337     }
1338
1339 bailout:
1340     return pcl3driverware;
1341
1342 #endif  // APDK_LINUX
1343
1344 } //IsPCL3DriverwareAvailable
1345
1346
1347 DISPLAY_STATUS DJ9xxVIP::ParseError(BYTE status_reg)
1348 {
1349     DBG1("DJ9xxVIP, parsing error info\n");
1350
1351     DRIVER_ERROR err = NO_ERROR;
1352     BYTE DevIDBuffer[DevIDBuffSize];
1353     char *pStr;
1354     int     iVersion = pSS->GetVIPVersion ();
1355
1356     if(IOMode.bDevID && iVersion < 6)
1357     {
1358         // If a bi-di cable was plugged in and everything was OK, let's see if it's still
1359         // plugged in and everything is OK
1360         err = pSS->GetDeviceID (DevIDBuffer, DevIDBuffSize, TRUE);
1361         if(err != NO_ERROR)
1362         {
1363             // job was bi-di but now something's messed up, probably cable unplugged
1364             return DISPLAY_COMM_PROBLEM;
1365         }
1366
1367         if ( (pStr=(char *)strstr((const char*)DevIDBuffer+2,";S:")) == NULL )
1368         {
1369             return DISPLAY_COMM_PROBLEM;
1370         }
1371
1372         // point to PrinterState
1373         BYTE b1,b2;
1374
1375         pStr+=5;   // 3 for ";S:", 2 for version -- point to first byte of "printer state"
1376         b1=*pStr;
1377
1378         if (b1=='9')
1379         {
1380             return DISPLAY_TOP_COVER_OPEN;
1381         }
1382
1383         if (iVersion < 3)
1384         {
1385             pStr += 12;     // point to "feature state"
1386         }
1387         else if (iVersion < 5)
1388         {
1389             pStr += 14;
1390         }
1391         else
1392         {
1393             pStr += 18;
1394         }
1395
1396         b1=*pStr++;
1397         b2=*pStr++;
1398         if ((b1=='0') && (b2=='9'))     // 09 = OOP state
1399         {
1400             DBG1("Out of Paper [from Encoded DevID]\n");
1401             return DISPLAY_OUT_OF_PAPER;
1402         }
1403
1404         if (b1 == '0' && (b2 == 'c' || b2 == 'C'))      // 0C - PhotoTray Mismatch
1405         {
1406
1407 /*
1408  *          PhotoTray is engaged, but requested paper size is larger than A6.
1409  *          It may also mean A6/Photo size is requested but photo tray is not engaged.
1410  */
1411
1412             DBG1("Photo Tray Mismatch [from Encoded DevID]\n");
1413             return DISPLAY_PHOTOTRAY_MISMATCH;
1414         }
1415
1416 //      Paper Jam or Paper Stall
1417
1418         if ((b1 == '1' && b2 == '0') ||        // Paper Jam
1419             (b1 == '0' && (b2 == 'e' || b2 == 'E')))
1420         {
1421             return DISPLAY_PAPER_JAMMED;
1422         }
1423
1424 //      Carriage Stall
1425
1426         if (b1 == '0' && (b2 == 'F' || b2 == 'f'))
1427         {
1428             return DISPLAY_ERROR_TRAP;
1429         }
1430
1431 //      Job Cancelled (AIO printer turn idle after job canceled)
1432         if ((b1=='0') && (b2=='5'))     // 05 = CNCL state
1433         {
1434             DBG1("Printing Canceled [from Encoded DevID]\n");
1435             return DISPLAY_PRINTING_CANCELED;
1436         }
1437
1438         // VerifyPenInfo will handle prompting the user
1439         // if this is a problem
1440         err = VerifyPenInfo ();
1441
1442         if(err != NO_ERROR)
1443         {
1444             // VerifyPenInfo returned an error, which can only happen when ToDevice
1445             // or GetDeviceID returns an error. Either way, it's BAD_DEVICE_ID or
1446             // IO_ERROR, both unrecoverable.  This is probably due to the printer
1447             // being turned off during printing, resulting in us not being able to
1448             // power it back on in VerifyPenInfo, since the buffer still has a
1449             // partial raster in it and we can't send the power-on command.
1450             return DISPLAY_COMM_PROBLEM;
1451         }
1452     }
1453
1454     // check for errors we can detect from the status reg
1455     if (IOMode.bStatus)
1456     {
1457         // Although DJ8XX is OOP, printer continues taking data and BUSY bit gets
1458         // set.  See IO_defs.h
1459         if ( DEVICE_IS_OOP(status_reg) )
1460         {
1461             DBG1("Out Of Paper [from status byte]\n");
1462             return DISPLAY_OUT_OF_PAPER;
1463         }
1464
1465         // DJ8XX doesn't go offline, so SELECT bit is set even when paper jammed.
1466         // See IO_defs.h
1467         if (DEVICE_PAPER_JAMMED(status_reg))
1468         {
1469             DBG1("Jammed [from status byte]\n");
1470             return DISPLAY_PAPER_JAMMED;
1471         }
1472 /*
1473  *      Do not process this. Malibu printers set the NFAULT bit low when a pen is
1474  *      missing, eventhough they support reserve mode printing. This causes us to
1475  *      report ERROR_TRAP message. Consequence is that we may not catch carriage
1476  *      stall, but should eventually result in time out.
1477         if (DEVICE_IO_TRAP(status_reg))
1478         {
1479             DBG1("Jammed or trapped [from status byte]\n");
1480             return DISPLAY_ERROR_TRAP;
1481         }
1482  */
1483     }
1484
1485     // don't know what the problem is-
1486     //  Is the PrinterAlive?
1487     if (pSS->PrinterIsAlive())
1488     {
1489         iTotal_SLOW_POLL_Count += iMax_SLOW_POLL_Count;
1490 #if defined(DEBUG) && (DBG_MASK & DBG_LVL1)
1491         printf("iTotal_SLOW_POLL_Count = %d\n",iTotal_SLOW_POLL_Count);
1492 #endif
1493         // -Note that iTotal_SLOW_POLL_Count is a multiple of
1494         //  iMax_SLOW_POLL_Count allowing us to check this
1495         //  on an absolute time limit - not relative to the number
1496         //  of times we happen to have entered ParseError.
1497         // -Also note that we have different thresholds for uni-di & bi-di.
1498         if(
1499             ((IOMode.bDevID == FALSE) && (iTotal_SLOW_POLL_Count >= 60)) ||
1500             ((IOMode.bDevID == TRUE)  && (iTotal_SLOW_POLL_Count >= 120))
1501           )
1502         {
1503             return DISPLAY_BUSY;
1504         }
1505         else
1506         {
1507             return DISPLAY_PRINTING;
1508         }
1509     }
1510     else
1511     {
1512         return DISPLAY_COMM_PROBLEM;
1513     }
1514 } //ParseError
1515
1516
1517 DRIVER_ERROR DJ9xxVIP::CleanPen()
1518 {
1519     const BYTE DJ990_User_Output_Page[] = {ESC, '%','P','u','i','f','p','.',
1520         'm','u','l','t','i','_','b','u','t','t','o','n','_','p','u','s','h',' ','3',';',
1521         'u','d','w','.','q','u','i','t',';',ESC,'%','-','1','2','3','4','5','X' };
1522
1523     DWORD length = sizeof(PEN_CLEAN_PML);
1524     DRIVER_ERROR err = pSS->ToDevice(PEN_CLEAN_PML, &length);
1525     ERRCHECK;
1526
1527     // send this page so that the user sees some output.  If you don't send this, the
1528     // pens get serviced but nothing prints out.
1529     length = sizeof(DJ990_User_Output_Page);
1530     return pSS->ToDevice(DJ990_User_Output_Page, &length);
1531 } //CleanPen
1532
1533
1534 #if defined(APDK_VIP_COLORFILTERING)
1535 /// ERNIE ////////////////////////////////////////////////////////////////
1536 BOOL TErnieFilter::Process(RASTERDATA* ImageData)
1537 {
1538         if (ImageData == NULL || (ImageData->rasterdata[COLORTYPE_COLOR] == NULL && ImageData->rasterdata[COLORTYPE_BLACK] == NULL))
1539         {
1540                 return FALSE;
1541         }
1542         else
1543         {
1544                 if (ImageData->rasterdata[COLORTYPE_COLOR])
1545                 {
1546                         submitRowToFilter(ImageData->rasterdata[COLORTYPE_COLOR]);
1547
1548                         if (ImageData->rasterdata[COLORTYPE_BLACK])
1549                         {
1550                                 memcpy(fBlackRowPtr[RowIndex], ImageData->rasterdata[COLORTYPE_BLACK], ImageData->rastersize[COLORTYPE_BLACK]);
1551                         }
1552                         BlackRasterSize[RowIndex++] = ImageData->rastersize[COLORTYPE_BLACK];
1553
1554                         if (RowIndex == 4)
1555                                 RowIndex = 0;
1556
1557                         // something ready after 4th time only
1558                         return (fNumberOfBufferedRows == 0);
1559                 }
1560                 else
1561                 {
1562                         iRastersReady = 1;
1563                 }
1564         }
1565         return TRUE;
1566 } //Process
1567
1568
1569 unsigned int TErnieFilter::GetOutputWidth(COLORTYPE  rastercolor)
1570 {
1571         if (rastercolor == COLORTYPE_COLOR)
1572         {
1573                 if (raster.rasterdata[COLORTYPE_COLOR] == NULL)
1574                         return 0;
1575                 else
1576                         return fRowWidthInPixels * BYTES_PER_PIXEL;
1577         }
1578         else
1579         {
1580                 if (raster.rasterdata[COLORTYPE_COLOR] == NULL)
1581                         return raster.rastersize[rastercolor];
1582                 else
1583                         return BlackRasterSize[iRastersDelivered-1];
1584         }
1585 } //GetOutputWidth
1586
1587
1588 BYTE* TErnieFilter::NextOutputRaster(COLORTYPE  rastercolor)
1589 {
1590         if (iRastersReady == 0)
1591                 return (BYTE*)NULL;
1592         if (rastercolor == COLORTYPE_COLOR)
1593         {
1594                 if (raster.rasterdata[COLORTYPE_COLOR] == NULL)
1595                 {
1596                         iRastersReady--;
1597                         return (BYTE*)NULL;
1598                 }
1599                 else
1600                 {
1601                         if (iRastersReady == 0)
1602                                 return (BYTE*)NULL;
1603
1604                         iRastersReady--;
1605
1606                         return fRowPtr[iRastersDelivered++];
1607                 }
1608         }
1609         else
1610         {
1611                 if (raster.rasterdata[COLORTYPE_COLOR] == NULL)
1612                 {
1613                         return raster.rasterdata[rastercolor];
1614                 }
1615                 else
1616                 {
1617                         if (BlackRasterSize[iRastersDelivered] == 0)
1618                                 return NULL;
1619                         else
1620                                 return fBlackRowPtr[iRastersDelivered];
1621                 }
1622         }
1623 } //NextOutputRaster
1624
1625
1626 void TErnieFilter::Flush()
1627 {
1628     writeBufferedRows();
1629     iRastersDelivered=0;
1630     fPixelOffsetIndex = 0;
1631     iRastersReady = fNumberOfBufferedRows;
1632     fNumberOfBufferedRows = 0;
1633 } //Flush
1634
1635 #endif //APDK_VIP_COLORFILTERING
1636
1637 inline uint32_t Mode10::get3Pixel
1638 (
1639     BYTE* pixAddress,
1640     int pixelOffset
1641 )
1642 {
1643     pixAddress += ((pixelOffset << 1) + pixelOffset);     //pixAddress += pixelOffset * 3;
1644
1645     BYTE r = *(pixAddress);
1646     BYTE g = *(pixAddress + 1);
1647     BYTE b = *(pixAddress + 2);
1648
1649     return (kWhite & ((r << 16) | (g << 8) | (b)));
1650
1651 //  unsigned int toReturn = *((unsigned int*)pixAddress); // load toReturn with XRGB
1652 //  toReturn &= kWhite; // Strip off unwanted X. EGW stripped lsb blue.
1653 } //get3Pixel
1654
1655
1656 void Mode10::put3Pixel
1657 (
1658     BYTE* pixAddress,
1659     int pixelOffset,
1660     uint32_t pixel
1661 )
1662 {
1663     pixAddress += ((pixelOffset << 1) + pixelOffset);     //pixAddress += pixelOffset * 3;
1664
1665     unsigned int temp = (pixel & kWhite);
1666
1667     *(pixAddress) = ((temp >> 16) & 0x000000FF);
1668     *(pixAddress + 1) = ((temp >> 8) & 0x000000FF);
1669     *(pixAddress + 2) = (temp & 0x000000FF);
1670
1671 } //put3Pixel
1672
1673
1674 unsigned short Mode10::ShortDelta
1675 (
1676     uint32_t lastPixel,
1677     uint32_t lastUpperPixel
1678 )
1679 {
1680     int dr,dg,db;
1681     int result;
1682
1683     dr = GetRed(lastPixel) - GetRed(lastUpperPixel);
1684     dg = GetGreen(lastPixel) - GetGreen(lastUpperPixel);
1685     db = GetBlue(lastPixel) - GetBlue(lastUpperPixel);
1686
1687     if ((dr <= 15) && (dr >= -16) && (dg <= 15) && (dg >= -16) && (db <= 30) && (db >= -32))
1688     {   // Note db is divided by 2 to double it's range from -16..15 to -32..30
1689         result = ((dr << 10) & 0x007C00) | (((dg << 5) & 0x0003E0) | ((db >> 1) & 0x01F) | 0x8000);   // set upper bit to signify short delta
1690     }
1691     else
1692     {
1693         result = 0;  // upper bit is zero to signify delta won't work
1694     }
1695
1696     return result;
1697 }
1698
1699 BOOL Mode10::Process
1700 (
1701     RASTERDATA* input
1702 )
1703 /****************************************************************************
1704 Initially written by Elden Wood
1705 August 1998
1706
1707 Similar to mode 9, though tailored for pixel data.
1708 For more information see the Bert Compression Format document.
1709
1710 This function compresses a single row per call.
1711 ****************************************************************************/
1712 {
1713     if (input==NULL || 
1714                 (input->rasterdata[COLORTYPE_COLOR]==NULL && input->rasterdata[COLORTYPE_BLACK]==NULL))    // flushing pipeline
1715     {
1716         Flush();
1717         return FALSE;
1718     }
1719
1720         if (myplane == COLORTYPE_BLACK || input->rasterdata[COLORTYPE_COLOR]==NULL)
1721         {
1722                 iRastersReady = 1;
1723                 compressedsize = 0;
1724                 if (seeded)
1725                 {
1726                         thePrinter->Send(ResetSeedrow, sizeof(ResetSeedrow));
1727             memset(SeedRow,0xFF,inputsize);
1728                         seeded = FALSE;
1729                 }
1730                 return TRUE;
1731         }
1732     unsigned int originalsize = input->rastersize[myplane];
1733         unsigned int size = input->rastersize[myplane];
1734
1735     unsigned char *seedRowPtr = (unsigned char*)SeedRow;
1736
1737     unsigned char *compressedDataPtr = compressBuf;
1738     unsigned char *curRowPtr =  (unsigned char*)input->rasterdata[myplane];
1739     unsigned int rowWidthInBytes = size;
1740
1741     ASSERT(curRowPtr);
1742     ASSERT(seedRowPtr);
1743     ASSERT(compressedDataPtr);
1744     ASSERT(rowWidthInBytes >= BYTES_PER_PIXEL);
1745     ASSERT((rowWidthInBytes % BYTES_PER_PIXEL) == 0);
1746
1747     unsigned char *compressedDataStart = compressedDataPtr;
1748     unsigned int lastPixel = (rowWidthInBytes / BYTES_PER_PIXEL) - 1;
1749
1750     // Setup sentinal value to replace last pixel of curRow. Simplifies future end condition checking.
1751     uint32_t realLastPixel = getPixel(curRowPtr, lastPixel);
1752
1753     uint32_t newLastPixel = realLastPixel;
1754     while ((getPixel(curRowPtr, lastPixel-1) == newLastPixel) ||
1755             (getPixel(seedRowPtr, lastPixel) == newLastPixel))
1756     {
1757         putPixel(curRowPtr, lastPixel, newLastPixel += 0x100); // add one to green.
1758     }
1759
1760     unsigned int curPixel = 0;
1761     unsigned int seedRowPixelCopyCount;
1762     unsigned int cachedColor = kWhite;
1763
1764     do // all pixels in row
1765     {
1766         unsigned char CMDByte = 0;
1767         int replacementCount;
1768
1769         // Find seedRowPixelCopyCount for upcoming copy
1770         seedRowPixelCopyCount = curPixel;
1771         while (getPixel(seedRowPtr, curPixel) == getPixel(curRowPtr, curPixel))
1772         {
1773             curPixel++;
1774         }
1775
1776         seedRowPixelCopyCount = curPixel - seedRowPixelCopyCount;
1777         ASSERT (curPixel <= lastPixel);
1778
1779         int pixelSource = 0;
1780
1781         if (curPixel == lastPixel) // On last pixel of row. RLE could also leave us on the last pixel of the row from the previous iteration.
1782         {
1783             putPixel(curRowPtr, lastPixel, realLastPixel);
1784
1785             if (getPixel(seedRowPtr, curPixel) == realLastPixel)
1786             {
1787                 goto mode10rtn;
1788             }
1789             else // code last pix as a literal
1790             {
1791
1792                 CMDByte = eLiteral;
1793                 pixelSource = eeNewPixel;
1794                 replacementCount = 1;
1795                 curPixel++;
1796             }
1797         }
1798         else // prior to last pixel of row
1799         {
1800             ASSERT(curPixel < lastPixel);
1801
1802             replacementCount = curPixel;
1803             uint32_t RLERun = getPixel(curRowPtr, curPixel);
1804
1805             curPixel++; // Adjust for next pixel.
1806             while (RLERun == getPixel(curRowPtr, curPixel)) // RLE
1807             {
1808                 curPixel++;
1809             }
1810             curPixel--; // snap back to current.
1811             replacementCount = curPixel - replacementCount;
1812             ASSERT(replacementCount >= 0);
1813
1814             if (replacementCount > 0) // Adjust for total occurance and move to next pixel to do.
1815             {
1816                 curPixel++;
1817                 replacementCount++;
1818
1819                 if (cachedColor == RLERun)
1820                 {
1821                     pixelSource = eeCachedColor;
1822                 }
1823                 else if (getPixel(seedRowPtr, curPixel-replacementCount+1) == RLERun)
1824                 {
1825                     pixelSource = eeNEPixel;
1826                 }
1827                 else if ((curPixel-replacementCount > 0) &&  (getPixel(curRowPtr, curPixel-replacementCount-1) == RLERun))
1828                 {
1829                     pixelSource = eeWPixel;
1830                 }
1831                 else
1832                 {
1833                     pixelSource = eeNewPixel;
1834                     cachedColor = RLERun;
1835                 }
1836
1837                 CMDByte = eRLE; // Set default for later.
1838
1839             }
1840
1841             if (curPixel == lastPixel)
1842             {
1843                 ASSERT(replacementCount > 0); // Already found some RLE pixels
1844
1845                 if (realLastPixel == RLERun) // Add to current RLE. Otherwise it'll be part of the literal from the seedrow section above on the next iteration.
1846                 {
1847                     putPixel(curRowPtr, lastPixel, realLastPixel);
1848                     replacementCount++;
1849                     curPixel++;
1850                 }
1851             }
1852
1853             if (0 == replacementCount) // no RLE so it's a literal by default.
1854             {
1855                 uint32_t tempPixel = getPixel(curRowPtr, curPixel);
1856
1857                 ASSERT(tempPixel != getPixel(curRowPtr, curPixel+1)); // not RLE
1858                 ASSERT(tempPixel != getPixel(seedRowPtr, curPixel)); // not seedrow copy
1859
1860                 CMDByte = eLiteral;
1861
1862                 if (cachedColor == tempPixel)
1863                 {
1864                     pixelSource = eeCachedColor;
1865
1866                 }
1867                 else if (getPixel(seedRowPtr, curPixel+1) == tempPixel)
1868                 {
1869                     pixelSource = eeNEPixel;
1870
1871                 }
1872                 else if ((curPixel > 0) &&  (getPixel(curRowPtr, curPixel-1) == tempPixel))
1873                 {
1874                     pixelSource = eeWPixel;
1875
1876                 }
1877                 else
1878                 {
1879
1880                     pixelSource = eeNewPixel;
1881                     cachedColor = tempPixel;
1882                 }
1883
1884                 replacementCount = curPixel;
1885                 uint32_t cachePixel;
1886                 uint32_t nextPixel = getPixel(curRowPtr, curPixel+1);
1887                 do
1888                 {
1889                     if (++curPixel == lastPixel)
1890                     {
1891                         putPixel(curRowPtr, lastPixel, realLastPixel);
1892                         curPixel++;
1893                         break;
1894                     }
1895                     cachePixel = nextPixel;
1896                 }
1897                 while ((cachePixel != (nextPixel = getPixel(curRowPtr, curPixel+1))) &&
1898                         (cachePixel != getPixel(seedRowPtr, curPixel)));
1899
1900                 replacementCount = curPixel - replacementCount;
1901
1902                 ASSERT(replacementCount > 0);
1903             }
1904         }
1905
1906         ASSERT(seedRowPixelCopyCount >= 0);
1907
1908         // Write out compressed data next.
1909         if (eLiteral == CMDByte)
1910         {
1911             ASSERT(replacementCount >= 1);
1912
1913             replacementCount -= 1; // normalize it
1914
1915             CMDByte |= pixelSource; // Could put this directly into CMDByte above.
1916             CMDByte |= MIN(3, seedRowPixelCopyCount) << 3;
1917             CMDByte |= MIN(7, replacementCount);
1918
1919             *compressedDataPtr++ = CMDByte;
1920
1921             if (seedRowPixelCopyCount >= 3)
1922             {
1923                 outputVLIBytesConsecutively(seedRowPixelCopyCount - 3, compressedDataPtr);
1924             }
1925
1926             replacementCount += 1; // denormalize it
1927
1928             int totalReplacementCount = replacementCount;
1929             int upwardPixelCount = 1;
1930
1931             if (eeNewPixel != pixelSource)
1932             {
1933                 replacementCount -= 1; // Do not encode 1st pixel of run since it comes from an alternate location.
1934                 upwardPixelCount = 2;
1935             }
1936
1937             for ( ; upwardPixelCount <= totalReplacementCount; upwardPixelCount++)
1938             {
1939                 ASSERT(totalReplacementCount >= upwardPixelCount);
1940
1941                 unsigned short compressedPixel = ShortDelta(    getPixel(curRowPtr, curPixel-replacementCount),
1942                                                                 getPixel(seedRowPtr, curPixel-replacementCount));
1943                 if (compressedPixel)
1944                 {
1945                     *compressedDataPtr++ = compressedPixel >> 8;
1946                     *compressedDataPtr++ = (unsigned char)compressedPixel;
1947
1948                 }
1949                 else
1950                 {
1951                     uint32_t uncompressedPixel = getPixel(curRowPtr, curPixel-replacementCount);
1952
1953                     uncompressedPixel >>= 1; // Lose the lsb of blue and zero out the msb of the 3 bytes.
1954
1955                     *compressedDataPtr++ = (BYTE)(uncompressedPixel >> 16);
1956                     *compressedDataPtr++ = (BYTE)(uncompressedPixel >> 8);
1957                     *compressedDataPtr++ = (BYTE)(uncompressedPixel);
1958
1959                 }
1960
1961                 if (((upwardPixelCount-8) % 255) == 0)  // See if it's time to spill a single VLI byte.
1962                 {
1963                     *compressedDataPtr++ = MIN(255, totalReplacementCount - upwardPixelCount);
1964                 }
1965
1966                 replacementCount--;
1967             }
1968         }
1969         else // RLE
1970         {
1971             ASSERT(eRLE == CMDByte);
1972             ASSERT(replacementCount >= 2);
1973
1974             replacementCount -= 2; // normalize it
1975
1976             CMDByte |= pixelSource; // Could put this directly into CMDByte above.
1977             CMDByte |= MIN(3, seedRowPixelCopyCount) << 3;
1978             CMDByte |= MIN(7, replacementCount);
1979
1980             *compressedDataPtr++ = CMDByte;
1981
1982             if (seedRowPixelCopyCount >= 3)
1983             {
1984                 outputVLIBytesConsecutively(seedRowPixelCopyCount - 3, compressedDataPtr);
1985             }
1986
1987             replacementCount += 2; // denormalize it
1988
1989             if (eeNewPixel == pixelSource)
1990             {
1991                 unsigned short compressedPixel = ShortDelta(getPixel(curRowPtr, curPixel - replacementCount),
1992                                                             getPixel(seedRowPtr, curPixel - replacementCount));
1993                 if (compressedPixel)
1994                 {
1995                     *compressedDataPtr++ = compressedPixel >> 8;
1996                     *compressedDataPtr++ = (unsigned char)compressedPixel;
1997                 }
1998                 else
1999                 {
2000                     uint32_t uncompressedPixel = getPixel(curRowPtr, curPixel - replacementCount);
2001
2002                     uncompressedPixel >>= 1;
2003
2004                     *compressedDataPtr++ = (BYTE)(uncompressedPixel >> 16);
2005                     *compressedDataPtr++ = (BYTE)(uncompressedPixel >> 8);
2006                     *compressedDataPtr++ = (BYTE)(uncompressedPixel);
2007                 }
2008             }
2009
2010             if (replacementCount-2 >= 7) outputVLIBytesConsecutively(replacementCount - (7+2), compressedDataPtr);
2011         }
2012     } while (curPixel <= lastPixel);
2013
2014 mode10rtn:
2015     size = compressedDataPtr - compressedDataStart; // return # of compressed bytes.
2016     compressedsize = size;
2017     memcpy(SeedRow, input->rasterdata[myplane], originalsize);
2018     seeded = TRUE;
2019     iRastersReady = 1;
2020     return TRUE;
2021 } //Process
2022
2023 BYTE* Mode10::NextOutputRaster(COLORTYPE color)
2024 // since we return 1-for-1, just return result first call
2025 {
2026         if (iRastersReady==0)
2027                 return (BYTE*)NULL;
2028
2029         if (color == COLORTYPE_BLACK)
2030         {
2031                 return raster.rasterdata[color];
2032         }
2033         else
2034         {
2035                 iRastersReady=0;
2036                 if (raster.rasterdata[color] != NULL)
2037                 {
2038                         return compressBuf;
2039                 }
2040                 else
2041                 {
2042                         return raster.rasterdata[color];
2043                 }
2044         }
2045 }
2046
2047 BYTE DJ9xxVIP::PhotoTrayStatus
2048 (
2049     BOOL bQueryPrinter
2050 )
2051 {
2052     DRIVER_ERROR err;
2053     char* pStr;
2054
2055     BYTE bDevIDBuff[DevIDBuffSize];
2056
2057     if (!IOMode.bDevID)
2058     {
2059         bQueryPrinter = FALSE;
2060     }
2061
2062     err = pSS->GetDeviceID(bDevIDBuff, DevIDBuffSize, bQueryPrinter);
2063     if (err!=NO_ERROR)
2064     {
2065         return 0;
2066     }
2067
2068     if ( (pStr=(char *)strstr((const char*)bDevIDBuff+2,";S:")) == NULL )
2069     {
2070         return 0;
2071     }
2072
2073     // skip over ";S:<version=2bytes><topcover><inklid><duplexer>"
2074     pStr += 8;
2075     BYTE b = *pStr;
2076     return b;
2077 } //PhotoTrayStatus
2078
2079
2080 BOOL DJ9xxVIP::PhotoTrayPresent
2081 (
2082     BOOL bQueryPrinter
2083 )
2084 {
2085     // for phototray present == 8
2086     return ((PhotoTrayStatus(bQueryPrinter) & 8) == 8);
2087 } //PhotoTrayInstalled
2088
2089
2090 PHOTOTRAY_STATE DJ9xxVIP::PhotoTrayEngaged
2091 (
2092     BOOL bQueryPrinter
2093 )
2094 {
2095
2096 /*
2097  *  When you add any new printer models to this class, make sure that the printer
2098  *  has the phototray sensor and reports the phototray state correctly.
2099  */
2100     // for phototray present and engaged == 9
2101     return ((PHOTOTRAY_STATE) ((PhotoTrayStatus(bQueryPrinter) & 9) == 9));
2102 } //PhotoTrayEngaged
2103
2104
2105 PAPER_SIZE DJ9xxVIP::MandatoryPaperSize()
2106 {
2107     if (PhotoTrayEngaged (TRUE))
2108         return PHOTO_SIZE;
2109     else return UNSUPPORTED_SIZE;   // code for "nothing mandatory"
2110 } //MandatoryPaperSize
2111
2112
2113 DRIVER_ERROR DJ9xxVIP::CheckInkLevel()
2114 {
2115     DRIVER_ERROR    err;
2116     char            *pStr;
2117     int             i;
2118
2119 //    BYTE bDevIDBuff[DevIDBuffSize];
2120
2121     if (!IOMode.bDevID)
2122     {
2123         return NO_ERROR;
2124     }
2125
2126 #if 0
2127 /*
2128  *  Check for unknown device id version.
2129  */
2130
2131     if ((pSS->GetVIPVersion ()) > 5)
2132     {
2133         return NO_ERROR;
2134     }
2135
2136     err = pSS->GetDeviceID(bDevIDBuff, DevIDBuffSize, TRUE);
2137     if (err!=NO_ERROR)
2138     {
2139         return err;
2140     }
2141
2142     if ( (pStr=(char *)strstr((const char*)bDevIDBuff+2,";S:")) == NULL )
2143     {
2144         return NO_ERROR;
2145     }
2146 #endif
2147
2148     // Skip to pen-count field
2149
2150     err = SetPenInfo (pStr, FALSE);
2151     if (err != NO_ERROR)
2152     {
2153         return NO_ERROR;
2154     }
2155
2156         /*
2157          *  VIPVersion = DevID Version + 1 - DevID Version no is 2 bytes following ;S:
2158          *  Version 00 and 01 report 12 bytes for status info
2159          *  Version 02 and onwards, report two additional bytes before pen info
2160          */
2161
2162     if (pSS->GetVIPVersion () == 1)
2163     {
2164
2165 //      DJ990 style DeviceID
2166
2167         // Next 3 should be 2C1
2168         // meaning 2 pens, first field is head/supply for K
2169
2170 //        pStr += 19;
2171         BYTE b1,b2,b3;
2172         b1=*pStr++; b2=*pStr++; b3=*pStr++;
2173         if ( (b1 != '2') || (b2 != 'C') || (b3 != '1'))
2174         {
2175             return NO_ERROR;
2176         }
2177
2178         // black pen
2179         pStr++;     // skip pen identifier
2180         BYTE blackink = *pStr - 48;     // convert from ascii
2181         // only look at low 3 bits
2182         blackink = blackink & 7;
2183
2184         // skip into color field
2185         pStr += 8;
2186         BYTE colorink = *pStr - 48;
2187         // only look at low 3 bits
2188         colorink = colorink & 7;
2189
2190         if ((blackink<5) && (colorink<5))
2191         {
2192             return NO_ERROR;
2193         }
2194
2195         if ((blackink>4) && (colorink>4))
2196         {
2197             return WARN_LOW_INK_BOTH_PENS;
2198         }
2199         if (blackink>4)
2200         {
2201             return WARN_LOW_INK_BLACK;
2202         }
2203         else
2204         {
2205             return WARN_LOW_INK_COLOR;
2206         }
2207     }
2208
2209 #if 0
2210     pStr += 21;
2211     if (pSS->GetVIPVersion () > 4)
2212     {
2213         pStr += 4;
2214     }
2215 #endif
2216
2217     int     numPens = 0;
2218     if (*pStr > '0' && *pStr < '9')
2219     {
2220         numPens = *pStr - '0';
2221     }
2222     else if (*pStr > 'A' && *pStr < 'F')
2223     {
2224         numPens = *pStr - 'A';
2225     }
2226     else if (*pStr > 'a' && *pStr < 'f')
2227     {
2228         numPens = *pStr - 'a';
2229     }
2230
2231     pStr++;
2232
2233     err = NO_ERROR;
2234     if (pSS->GetVIPVersion () == 3)
2235     {
2236         for (i = 0; i < numPens; i++, pStr += 4)
2237         {
2238             switch (*pStr)
2239             {
2240                 case '5':
2241                 {
2242                     if ((*(pStr+1) & 0xf3) > 1)
2243                     {
2244                         if (err != NO_ERROR)
2245                         {
2246                             err = WARN_LOW_INK_MULTIPLE_PENS;
2247                         }
2248                         else
2249                         {
2250                             err = WARN_LOW_INK_BLACK;
2251                         }
2252                     }
2253                     break;
2254                 }
2255                 case '6':
2256                 {
2257                     if ((*(pStr+1) & 0xf3) > 1)
2258                     {
2259                         if (err != NO_ERROR)
2260                         {
2261                             err = WARN_LOW_INK_MULTIPLE_PENS;
2262                         }
2263                         else
2264                         {
2265                             err = WARN_LOW_INK_CYAN;
2266                         }
2267                     }
2268                     break;
2269                 }
2270                 case '7':
2271                 {
2272                     if ((*(pStr+1) & 0xf3) > 1)
2273                     {
2274                         if (err != NO_ERROR)
2275                         {
2276                             err = WARN_LOW_INK_MULTIPLE_PENS;
2277                         }
2278                         else
2279                         {
2280                             err = WARN_LOW_INK_MAGENTA;
2281                         }
2282                     }
2283
2284                     break;
2285                 }
2286                 case '8':
2287                 {
2288                     if ((*(pStr+1) & 0xf3) > 1)
2289                     {
2290                         if (err != NO_ERROR)
2291                         {
2292                             err = WARN_LOW_INK_MULTIPLE_PENS;
2293                         }
2294                         else
2295                         {
2296                             err = WARN_LOW_INK_YELLOW;
2297                         }
2298                     }
2299                     break;
2300                 }
2301             }
2302         }
2303         return err;
2304     }
2305
2306         BYTE    penInfoBits[4];
2307     BYTE    blackink = 0;
2308     BYTE    colorink = 0;
2309     BYTE    photoink = 0;
2310     BYTE    greyink = 0;
2311
2312     for (i = 0; i < numPens; i++, pStr += 8)
2313     {
2314         AsciiHexToBinary (penInfoBits, pStr, 8);
2315
2316         if ((penInfoBits[0] & 0x40) != 0x40)        // if Bit 31 is 1, this is not a pen
2317         {
2318             continue;
2319         }
2320         int penColor = penInfoBits[0] & 0x3F;
2321         switch (penColor)
2322         {
2323             case 1:
2324                 blackink =  penInfoBits[1] & 0x7;
2325                 break;
2326             case 2:
2327                 colorink =  penInfoBits[1] & 0x7;
2328                 break;
2329             case 3:
2330                 photoink =  penInfoBits[1] & 0x7;
2331                 break;
2332             case 10:
2333                 greyink =  penInfoBits[1] & 0x7;
2334                 break;
2335             case 4:
2336             case 5:
2337             case 6:
2338             case 7:
2339             case 8:
2340             case 9:
2341                 colorink = penInfoBits[1] & 0x7;   // REVISIT: these are C, M, Y respectively
2342                 break;
2343             default:
2344                 break;
2345         }
2346     }
2347     if (blackink < 2 && colorink < 2 && photoink < 2 && greyink < 2)
2348     {
2349         return NO_ERROR;
2350     }
2351     else if (blackink > 1 && colorink > 1 && photoink > 1)
2352     {
2353         return WARN_LOW_INK_COLOR_BLACK_PHOTO;
2354     }
2355     else if (greyink > 1 && colorink > 1 && photoink > 1)
2356     {
2357         return WARN_LOW_INK_COLOR_GREY_PHOTO;
2358     }
2359     else if (blackink > 1 && colorink > 1)
2360     {
2361         return WARN_LOW_INK_BOTH_PENS;
2362     }
2363     else if (blackink > 1 && photoink > 1)
2364     {
2365         return WARN_LOW_INK_BLACK_PHOTO;
2366     }
2367     else if (greyink > 1 && colorink > 1)
2368     {
2369         return WARN_LOW_INK_COLOR_GREY;
2370     }
2371     else if (greyink > 1 && photoink > 1)
2372     {
2373         return WARN_LOW_INK_GREY_PHOTO;
2374     }
2375     else if (colorink > 1 && photoink > 1)
2376     {
2377         return WARN_LOW_INK_COLOR_PHOTO;
2378     }
2379     else if (blackink > 1)
2380     {
2381         return WARN_LOW_INK_BLACK;
2382     }
2383     else if (colorink > 1)
2384     {
2385         return WARN_LOW_INK_COLOR;
2386     }
2387     else if (photoink > 1)
2388     {
2389         return WARN_LOW_INK_PHOTO;
2390     }
2391     else if (greyink > 1)
2392     {
2393         return WARN_LOW_INK_GREY;
2394         }
2395     else if (colorink > 1)
2396     {
2397         return WARN_LOW_INK_COLOR;
2398     }
2399         else
2400         {
2401                 return NO_ERROR;
2402         }
2403 } //CheckInkLevel
2404
2405 APDK_END_NAMESPACE
2406
2407 #endif  //APDK_DJ9xxVIP