1 /*****************************************************************************\
2 systemservice.cpp : Implimentation for the SystemServices class
4 Copyright (c) 1996 - 2001, Hewlett-Packard Co.
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 3. Neither the name of Hewlett-Packard nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
20 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
22 NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24 TO, PATENT INFRINGEMENT; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25 OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 \*****************************************************************************/
35 #endif // APDK_CAPTURE
39 // Constructor instantiates the DeviceRegistry.
40 // Real work done in InitDeviceComm, called from derived
43 This method constructs a SystemServices object. This is the first step in the
45 Check constructor_error before continuing.
47 SystemServices::SystemServices()
48 : constructor_error(NO_ERROR),
49 #if defined(APDK_CAPTURE)
56 strModel[0] = strPens[0] = '\0';
59 DR = new DeviceRegistry();
65 memset (strDevID, 0, DevIDBuffSize);
70 This method is a destructor, called when the instance of SystemServices is
71 deleted or goes out of scope.
73 SystemServices::~SystemServices()
78 #if defined(APDK_CAPTURE)
83 DBG1("deleting SystemServices\n");
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.
91 BOOL SystemServices::PrinterIsAlive()
95 // Technically, this function should not even be
96 // called if IOMode.bStatus is known to be FALSE
\r
97 if (!IOMode.bStatus)
\r
99 if( GetStatusInfo(&status_reg) == FALSE )
101 DBG1("PrinterIsAlive: No Status-Byte Available (Default = TRUE)\n");
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)))
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");
116 DBG1("PrinterIsAlive: returning FALSE\n");
119 return (DEVICE_IS_OK(status_reg));
123 Same as host-supplied FreeMem, with extra safety check
126 DRIVER_ERROR SystemServices::FreeMemory(void *ptr)
131 // printf("FreeMemory freeing %p\n",ptr);
139 This method tries to get the device id back from the printer and does some basic verification.
141 DRIVER_ERROR SystemServices::GetDeviceID(BYTE* strID, int iSize, BOOL bQuery)
144 if (iSize < 3) // must have at least enough space for count bytes and NULL terminator
146 return(SYSTEM_ERROR);
149 memset (strID, 0, iSize);
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';
159 // we are going to try more then once because some printers lie and this
160 // specifically fixes problems with the DJ630 & DJ640 printers.
162 for(i = 0; i < 20; i++)
165 if((ReadDeviceID(strID, iSize) != NO_ERROR))
167 DBG1("Error from ReadDeviceID or No DevID Available\n");
168 if(BusyWait((DWORD)100) == JOB_CANCELED)
172 continue; // go back and try again
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)
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')))
190 DBG1("Successful' DevID request was a lie. Retry...waiting 100 ms\n");
191 if(BusyWait((DWORD)100) == JOB_CANCELED)
195 continue; // go back and try again
199 // If either of the first two bytes is 0, byte count is there, replace them.
201 if (strID[0] == 0 || strID[1] == 0)
203 strID[0] = strID[1] = ' ';
205 //DBG1("HPPCL: ReadDeviceID [%hs]\n", strID+2);
212 return BAD_DEVICE_ID;
217 // for use when string doesn't have to be re-fetched from printer
219 if (DevIDBuffSize > iSize)
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);
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
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'))
243 return BAD_DEVICE_ID;
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:"))
255 return BAD_DEVICE_ID;
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.
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.
278 // Calls: OpenPort,PrinterIsAlive,DisplayPrinterStatus,BusyWait,
279 // GetDeviceID,DeviceRegistry::ParseDevIDString.
280 // Sets: hPort,IOMode, strModel, strPens
282 DRIVER_ERROR err = NO_ERROR;
283 BOOL ErrorDisplayed = FALSE;
286 // Check whether this system supports passing back a status-byte
287 if( GetStatusInfo(&temp) == FALSE )
289 DBG1("InitDeviceComm: No Status-Byte Available\n");
291 else IOMode.bStatus = TRUE;
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);
297 if ( err == NO_ERROR )
299 DBG1("InitDeviceComm: DevID request successful\n");
300 IOMode.bDevID = TRUE;
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 )
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) )
316 // Printer is actually turned off
317 while(PrinterIsAlive() == FALSE)
319 DBG1("PrinterIsAlive returned FALSE\n");
320 ErrorDisplayed = TRUE;
321 DisplayPrinterStatus(DISPLAY_NO_PRINTER_FOUND);
323 if(BusyWait(500) == JOB_CANCELED)
326 if(ErrorDisplayed == TRUE)
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)
334 err = GetDeviceID(strDevID, DevIDBuffSize, TRUE);
335 if ( err == NO_ERROR )
337 DBG1("InitDeviceComm: DevID request successful\n");
338 IOMode.bDevID = TRUE;
342 // else... we have 8xx/9xx with an out-of-paper error
343 // which we will catch in the I/O handling
349 DBG1("InitDeviceComm: No DeviceID Available\n");
353 err = DR->ParseDevIDString((const char*)strDevID, strModel, &VIPVersion, strPens);
357 // The DevID we got is actually garbage!
358 DBG1("InitDeviceComm: The DevID string is invalid!\n");
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
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.
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.
384 DRIVER_ERROR SystemServices::GetECPStatus(BYTE *pStatusString,int *pECPLength, int ECPChannel)
386 pStatusString = NULL;
389 return UNSUPPORTED_FUNCTION;
392 //! reconcile printer's preferred settings with reality
393 void SystemServices::AdjustIO(IO_MODE IM, const char* model)
395 IOMode.bStatus=IM.bStatus && IOMode.bStatus;
396 IOMode.bDevID =IM.bDevID && IOMode.bDevID;
399 strncpy(strModel,model, sizeof(strModel));