Tizen 2.1 base
[platform/upstream/hplip.git] / prnt / hpijs / systemservices.cpp
1 /*****************************************************************************\
2   systemservice.cpp : Implimentation for the SystemServices class
3
4   Copyright (c) 1996 - 2001, 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 #include "header.h"
32 #include "io_defs.h"
33 #ifdef APDK_CAPTURE
34 #include "script.h"
35 #endif // APDK_CAPTURE
36
37 APDK_BEGIN_NAMESPACE
38
39 // Constructor instantiates the DeviceRegistry.
40 // Real work done in InitDeviceComm, called from derived
41 // class constructor.
42 /*!
43 This method constructs a SystemServices object. This is the first step in the
44 calling sequence.
45 Check constructor_error before continuing.
46 */
47 SystemServices::SystemServices()
48     : constructor_error(NO_ERROR),
49 #if defined(APDK_CAPTURE)
50     pScripter(NULL),
51     Capturing(FALSE),
52 #endif
53     iSendBufferSize(4096)
54 {
55
56     strModel[0] = strPens[0] = '\0';
57     VIPVersion = 0;
58
59     DR = new DeviceRegistry();
60     // DR can't fail
61
62     IOMode.bDevID=FALSE;
63     IOMode.bStatus=FALSE;
64     IOMode.bUSB=FALSE;
65     memset (strDevID, 0, DevIDBuffSize);
66
67 }
68
69 /*!
70 This method is a destructor, called when the instance of SystemServices is
71 deleted or goes out of scope.
72 */
73 SystemServices::~SystemServices()
74 {
75
76     delete DR;
77
78 #if defined(APDK_CAPTURE)
79     if (pScripter)
80         delete pScripter;
81 #endif
82
83 DBG1("deleting SystemServices\n");
84 }
85
86 /*!
87 Tests communication with printer.  It calls host supplied GetStatusInfo.
88 \return TRUE if communication with printer is working.
89 \note This implementation is appropriate for Parallel bus only.
90 */
91 BOOL SystemServices::PrinterIsAlive()
92 {
93     BYTE status_reg;
94
95     // Technically, this function should not even be
96     // called if IOMode.bStatus is known to be FALSE\r
97     if (!IOMode.bStatus)\r
98         return TRUE;
99     if( GetStatusInfo(&status_reg) == FALSE )
100     {
101         DBG1("PrinterIsAlive: No Status-Byte Available (Default = TRUE)\n");
102         return TRUE;
103     }
104
105 #define DJ6XX_OFF       (0xF8)
106 #define DJ400_OFF       (0xC0)
107 // sometimes the DJ400 reports a status byte of C8 when it's turned off
108 #define DJ400_OFF_BOGUS (0xC8)
109 #define DEVICE_IS_OK(reg) (!((reg == DJ6XX_OFF) || (reg == DJ400_OFF) || (reg == DJ400_OFF_BOGUS)))
110
111 #if defined(APDK_DEBUG) && (DBG_MASK & DBG_LVL1)
112     printf("status reg is 0x%02x\n",status_reg);
113     if (DEVICE_IS_OK(status_reg))
114         DBG1("PrinterIsAlive: returning TRUE\n");
115     else
116         DBG1("PrinterIsAlive: returning FALSE\n");
117 #endif
118
119     return (DEVICE_IS_OK(status_reg));
120 }
121
122 /*!
123  Same as host-supplied FreeMem, with extra safety check
124  for null pointer.
125 */
126 DRIVER_ERROR SystemServices::FreeMemory(void *ptr)
127 {
128     if (ptr == NULL)
129         return SYSTEM_ERROR;
130
131 //      printf("FreeMemory freeing %p\n",ptr);
132     FreeMem((BYTE*)ptr);
133
134  return NO_ERROR;
135 }
136
137
138 /*!
139 This method tries to get the device id back from the printer and does some basic verification.
140 */
141 DRIVER_ERROR SystemServices::GetDeviceID(BYTE* strID, int iSize, BOOL bQuery)
142 {
143
144     if (iSize < 3)  // must have at least enough space for count bytes and NULL terminator
145     {
146         return(SYSTEM_ERROR);
147     }
148
149         memset (strID, 0, iSize);
150
151     if (bQuery)
152     {
153         // initialize the first 3 bytes to NULL (1st 2 bytes may be binary count of string
154         // length so need to clear them as well as the "real" start of the string)
155         // so that if ReadDeviceID() does nothing with buffer we won't act upon what
156         // was in the buffer before calling it
157         strID[0] = strID[1] = strID[2] = '\0';
158
159         // we are going to try more then once because some printers lie and this
160         // specifically fixes problems with the DJ630 & DJ640 printers.
161         int i = 0;
162         for(i = 0; i < 20; i++)
163         {
164             // get the string
165             if((ReadDeviceID(strID, iSize) != NO_ERROR))
166             {
167                 DBG1("Error from ReadDeviceID or No DevID Available\n");
168                 if(BusyWait((DWORD)100) == JOB_CANCELED)
169                 {
170                     return JOB_CANCELED;
171                 }
172                 continue;  // go back and try again
173             }
174             // look for the existence of either of the defined manufacturer fields in the string
175             // (need to look starting at strID[0] and at strID[2] since the first 2 bytes may or
176             // may not be binary count bytes, one of which could be a binary 0 (NULL) which strstr()
177             // will interpret as the end of string)
178             else
179             {
180                 if ((!strstr((const char*)strID, "MFG:") &&
181                     !strstr((const char*)strID+2, "MFG:") &&
182                     !strstr((const char*)strID, "MANUFACTURER:") &&
183                     !strstr((const char*)strID+2, "MANUFACTURER:")) ||
184                     (!strstr((const char*)strID, "MDL:") &&
185                     !strstr((const char*)strID+2, "MDL:") &&
186                     !strstr((const char*)strID, "MODEL:") &&
187                     !strstr((const char*)strID+2, "MODEL:")) ||
188                     ((strID[0] == '\0') && (strID[1] == '\0')))
189                 {
190                     DBG1("Successful' DevID request was a lie.  Retry...waiting 100 ms\n");
191                     if(BusyWait((DWORD)100) == JOB_CANCELED)
192                     {
193                         return JOB_CANCELED;
194                     }
195                     continue;  // go back and try again
196                 }
197                 else
198                 {
199                     // If either of the first two bytes is 0, byte count is there, replace them.
200
201                     if (strID[0] == 0 || strID[1] == 0)
202                     {
203                         strID[0] = strID[1] = ' ';
204                     }
205                     //DBG1("HPPCL: ReadDeviceID [%hs]\n", strID+2);
206                     break; // SUCCESS!
207                 }
208             }
209         }
210         if(i >= 20)
211         {
212             return BAD_DEVICE_ID;
213         }
214     }
215     else
216     {
217         // for use when string doesn't have to be re-fetched from printer
218
219         if (DevIDBuffSize > iSize)
220         {
221             return SYSTEM_ERROR;
222         }
223
224         // the first 2 bytes may be binary so could be 0 (NULL) so can't use strcpy
225         // (could get strlen of strDevID if start @ strDevID+2 and then add 2
226         //  if do this it wouldn't require that caller's buffer be >=
227         //  DevIDBuffSize, only that is it longer that actual devID string read)
228         memcpy(strID, strDevID, DevIDBuffSize);
229     }
230     return NO_ERROR;
231
232     // This is old code from before the 630, 640 loop fix was done (above).  This can
233     // eventually be removed.
234     // check the read (or copied) DeviceID string for validity
235
236     // check what may be the binary count of the string length (some platforms return
237     // the raw DeviceID in which the 1st 2 bytes are a binary count of the string length,
238     // other platforms strip off these count bytes)
239     // if they are a binary count they shouldn't be zero, and if they aren't a binary
240     // count they also shouldn't be zero (NULL) since that would mean end of string
241 /*    if ((strID[0] == '\0') && (strID[1] == '\0'))
242     {
243         return BAD_DEVICE_ID;
244     }
245
246     // look for the existence of either of the defined manufacturer fields in the string
247     // (need to look starting at strID[0] and at strID[2] since the first 2 bytes may or
248     //  may not be binary count bytes, one of which could be a binary 0 (NULL) which strstr()
249     //  will interpret as the end of string)
250     if (!strstr((const char*)strID, "MFG:") &&
251         !strstr((const char*)strID+2, "MFG:") &&
252         !strstr((const char*)strID, "MANUFACTURER:") &&
253         !strstr((const char*)strID+2, "MANUFACTURER:"))
254     {
255         return BAD_DEVICE_ID;
256     }*/
257
258 } //GetDeviceID
259
260
261 /*!
262 Mandatory call to be inserted in derived constructor.
263 This method tries to establish communications with printer and identify it.
264 The derived SystemServices constructor must call this base-class routine.
265 */
266 DRIVER_ERROR SystemServices::InitDeviceComm()
267 // Must be called from derived class constructor.
268 // (Base class must be constructed before system calls
269 //  below can be made.)
270 // Opens the port, looks for printer and
271 // dialogues with user if none found;
272 // then attempts to read and parse device ID string --
273 // if successful, sets IOMode.bDevID to TRUE (strings stored
274 // for retrieval by PrintContext).
275 // Returns an error only if user cancelled. Otherwise
276 // no error even if unidi.
277 //
278 // Calls: OpenPort,PrinterIsAlive,DisplayPrinterStatus,BusyWait,
279 //   GetDeviceID,DeviceRegistry::ParseDevIDString.
280 // Sets:    hPort,IOMode, strModel, strPens
281 {
282     DRIVER_ERROR err = NO_ERROR;
283     BOOL ErrorDisplayed = FALSE;
284     BYTE temp;
285
286     // Check whether this system supports passing back a status-byte
287     if( GetStatusInfo(&temp) == FALSE )
288     {
289         DBG1("InitDeviceComm:  No Status-Byte Available\n");
290     }
291     else IOMode.bStatus = TRUE;
292
293     // Check whether we can get a DeviceID - this may
294     // still fail if the device is just turned off
295     err = GetDeviceID(strDevID, DevIDBuffSize, TRUE);
296
297     if ( err == NO_ERROR )
298     {
299         DBG1("InitDeviceComm:  DevID request successful\n");
300         IOMode.bDevID = TRUE;
301     }
302
303
304     // PrinterIsAlive is arbitrary if we can't get the status-byte.
305     // This check is also critical so a true uni-di system does not sit
306     // in a loop informing the user to turn on the printer.
307     if ( IOMode.bStatus == TRUE )
308     {
309         // Make sure a printer is there, turned on and connected
310         // before we go any further.  This takes some additional checking
311         // due to the fact that the 895 returns a status byte of F8 when
312         // it's out of paper, the same as a 600 when it's turned off.
313         // 895 can get a devID even when 'off' so we'll key off that logic.
314         if ( (err != NO_ERROR) && (PrinterIsAlive() == FALSE) )
315         {
316             // Printer is actually turned off
317             while(PrinterIsAlive() == FALSE)
318             {
319                 DBG1("PrinterIsAlive returned FALSE\n");
320                 ErrorDisplayed = TRUE;
321                 DisplayPrinterStatus(DISPLAY_NO_PRINTER_FOUND);
322
323                 if(BusyWait(500) == JOB_CANCELED)
324                     return JOB_CANCELED;
325             }
326             if(ErrorDisplayed == TRUE)
327             {
328                 DisplayPrinterStatus(DISPLAY_PRINTING);
329                 // if they just turned on/connected the printer,
330                 // delay a bit to let it initialize
331                 if(BusyWait(2000) == JOB_CANCELED)
332                     return JOB_CANCELED;
333
334                 err = GetDeviceID(strDevID, DevIDBuffSize, TRUE);
335                 if ( err == NO_ERROR )
336                 {
337                     DBG1("InitDeviceComm:  DevID request successful\n");
338                     IOMode.bDevID = TRUE;
339                 }
340             }
341         }
342         // else... we have 8xx/9xx with an out-of-paper error
343         // which we will catch in the I/O handling
344
345     }
346
347     if (err!=NO_ERROR)
348     {
349         DBG1("InitDeviceComm:  No DeviceID Available\n");
350         return NO_ERROR;
351     }
352
353     err = DR->ParseDevIDString((const char*)strDevID, strModel, &VIPVersion, strPens);
354
355     if (err!=NO_ERROR)
356     {
357         // The DevID we got is actually garbage!
358         DBG1("InitDeviceComm:  The DevID string is invalid!\n");
359         IOMode.bDevID=FALSE;
360     }
361
362     return NO_ERROR;
363 }
364
365
366 /*!
367 This function will open an ECP I/O channel to the printer and retrieve a
368 given number of bytes from it. Because ECP is a 1284 protocol, this
369 function is only relevant for 1284 compliant parallel I/O connectivity.
370 Currently, only the DeskJet 4xx Series of printers requires implementation
371 of this function. Because of the non-standard nature of this function, it
372 is expected that the sample code supplied in ECPSample.cpp will be heavily
373 leveraged during implementation of this function in the derived SystemServices
374 class.
375
376 \note  The DJ400 & DJ540 code was written as a special for a specific host.
377 DJ400 & DJ500 are not supported by the APDK and there is no  help with
378 communication issues with these printers.
379
380 \param pStatusString The destination of the set of retrieved status bytes.
381 \param pECPLength The number of retrieved bytes.
382 \param ECPChannel The ECP channel number to be opened and read.
383 */
384 DRIVER_ERROR SystemServices::GetECPStatus(BYTE *pStatusString,int *pECPLength, int ECPChannel)
385 {
386     pStatusString = NULL;
387     *pECPLength = 0;
388
389     return UNSUPPORTED_FUNCTION;
390 }
391
392 //! reconcile printer's preferred settings with reality
393 void SystemServices::AdjustIO(IO_MODE IM, const char* model)
394 {
395     IOMode.bStatus=IM.bStatus && IOMode.bStatus;
396     IOMode.bDevID =IM.bDevID  && IOMode.bDevID;
397
398     if (model)
399         strncpy(strModel,model, sizeof(strModel));
400 }
401
402 APDK_END_NAMESPACE
403