/*! This method tries to get the device id back from the printer and does some basic verification. */ DRIVER_ERROR SystemServices::GetDeviceID(BYTE* strID, int iSize, BOOL bQuery) { if (iSize < 3) // must have at least enough space for count bytes and NULL terminator { return(SYSTEM_ERROR); } memset (strID, 0, iSize); if (bQuery) { // initialize the first 3 bytes to NULL (1st 2 bytes may be binary count of string // length so need to clear them as well as the "real" start of the string) // so that if ReadDeviceID() does nothing with buffer we won't act upon what // was in the buffer before calling it strID[0] = strID[1] = strID[2] = '\0'; // we are going to try more then once because some printers lie and this // specifically fixes problems with the DJ630 & DJ640 printers. int i = 0; for(i = 0; i < 20; i++) { // get the string if((ReadDeviceID(strID, iSize) != NO_ERROR)) { DBG1("Error from ReadDeviceID or No DevID Available\n"); if(BusyWait((DWORD)100) == JOB_CANCELED) { return JOB_CANCELED; } continue; // go back and try again } // look for the existence of either of the defined manufacturer fields in the string // (need to look starting at strID[0] and at strID[2] since the first 2 bytes may or // may not be binary count bytes, one of which could be a binary 0 (NULL) which strstr() // will interpret as the end of string) else { if ((!strstr((const char*)strID, "MFG:") && !strstr((const char*)strID+2, "MFG:") && !strstr((const char*)strID, "MANUFACTURER:") && !strstr((const char*)strID+2, "MANUFACTURER:")) || (!strstr((const char*)strID, "MDL:") && !strstr((const char*)strID+2, "MDL:") && !strstr((const char*)strID, "MODEL:") && !strstr((const char*)strID+2, "MODEL:")) || ((strID[0] == '\0') && (strID[1] == '\0'))) { DBG1("Successful' DevID request was a lie. Retry...waiting 100 ms\n"); if(BusyWait((DWORD)100) == JOB_CANCELED) { return JOB_CANCELED; } continue; // go back and try again } else { // If either of the first two bytes is 0, byte count is there, replace them. if (strID[0] == 0 || strID[1] == 0) { strID[0] = strID[1] = ' '; } //DBG1("HPPCL: ReadDeviceID [%hs]\n", strID+2); break; // SUCCESS! } } } if(i >= 20) { return BAD_DEVICE_ID; } } else { // for use when string doesn't have to be re-fetched from printer if (DevIDBuffSize > iSize) { return SYSTEM_ERROR; } // the first 2 bytes may be binary so could be 0 (NULL) so can't use strcpy // (could get strlen of strDevID if start @ strDevID+2 and then add 2 // if do this it wouldn't require that caller's buffer be >= // DevIDBuffSize, only that is it longer that actual devID string read) memcpy(strID, strDevID, DevIDBuffSize); } return NO_ERROR; // This is old code from before the 630, 640 loop fix was done (above). This can // eventually be removed. // check the read (or copied) DeviceID string for validity // check what may be the binary count of the string length (some platforms return // the raw DeviceID in which the 1st 2 bytes are a binary count of the string length, // other platforms strip off these count bytes) // if they are a binary count they shouldn't be zero, and if they aren't a binary // count they also shouldn't be zero (NULL) since that would mean end of string /* if ((strID[0] == '\0') && (strID[1] == '\0')) { return BAD_DEVICE_ID; } // look for the existence of either of the defined manufacturer fields in the string // (need to look starting at strID[0] and at strID[2] since the first 2 bytes may or // may not be binary count bytes, one of which could be a binary 0 (NULL) which strstr() // will interpret as the end of string) if (!strstr((const char*)strID, "MFG:") && !strstr((const char*)strID+2, "MFG:") && !strstr((const char*)strID, "MANUFACTURER:") && !strstr((const char*)strID+2, "MANUFACTURER:")) { return BAD_DEVICE_ID; }*/ } //GetDeviceID
/*! Mandatory call to be inserted in derived constructor. This method tries to establish communications with printer and identify it. The derived SystemServices constructor must call this base-class routine. */ DRIVER_ERROR SystemServices::InitDeviceComm() // Must be called from derived class constructor. // (Base class must be constructed before system calls // below can be made.) // Opens the port, looks for printer and // dialogues with user if none found; // then attempts to read and parse device ID string -- // if successful, sets IOMode.bDevID to TRUE (strings stored // for retrieval by PrintContext). // Returns an error only if user cancelled. Otherwise // no error even if unidi. // // Calls: OpenPort,PrinterIsAlive,DisplayPrinterStatus,BusyWait, // GetDeviceID,DeviceRegistry::ParseDevIDString. // Sets: hPort,IOMode, strModel, strPens { DRIVER_ERROR err = NO_ERROR; BOOL ErrorDisplayed = FALSE; BYTE temp; // Check whether this system supports passing back a status-byte if( GetStatusInfo(&temp) == FALSE ) { DBG1("InitDeviceComm: No Status-Byte Available\n"); } else IOMode.bStatus = TRUE; // Check whether we can get a DeviceID - this may // still fail if the device is just turned off err = GetDeviceID(strDevID, DevIDBuffSize, TRUE); if ( err == NO_ERROR ) { DBG1("InitDeviceComm: DevID request successful\n"); IOMode.bDevID = TRUE; } // PrinterIsAlive is arbitrary if we can't get the status-byte. // This check is also critical so a true uni-di system does not sit // in a loop informing the user to turn on the printer. if ( IOMode.bStatus == TRUE ) { // Make sure a printer is there, turned on and connected // before we go any further. This takes some additional checking // due to the fact that the 895 returns a status byte of F8 when // it's out of paper, the same as a 600 when it's turned off. // 895 can get a devID even when 'off' so we'll key off that logic. if ( (err != NO_ERROR) && (PrinterIsAlive() == FALSE) ) { // Printer is actually turned off while(PrinterIsAlive() == FALSE) { DBG1("PrinterIsAlive returned FALSE\n"); ErrorDisplayed = TRUE; DisplayPrinterStatus(DISPLAY_NO_PRINTER_FOUND); if(BusyWait(500) == JOB_CANCELED) return JOB_CANCELED; } if(ErrorDisplayed == TRUE) { DisplayPrinterStatus(DISPLAY_PRINTING); // if they just turned on/connected the printer, // delay a bit to let it initialize if(BusyWait(2000) == JOB_CANCELED) return JOB_CANCELED; err = GetDeviceID(strDevID, DevIDBuffSize, TRUE); if ( err == NO_ERROR ) { DBG1("InitDeviceComm: DevID request successful\n"); IOMode.bDevID = TRUE; } } } // else... we have 8xx/9xx with an out-of-paper error // which we will catch in the I/O handling } if (err!=NO_ERROR) { DBG1("InitDeviceComm: No DeviceID Available\n"); return NO_ERROR; } err = DR->ParseDevIDString((const char*)strDevID, strModel, &VIPVersion, strPens); if (err!=NO_ERROR) { // The DevID we got is actually garbage! DBG1("InitDeviceComm: The DevID string is invalid!\n"); IOMode.bDevID=FALSE; } return NO_ERROR; }
void CCommandProcessor::ParseCommand ( const char * const cmdBegin, const uint64_t currentTime ) { const char * const cmdEnd = SkipCharsNotInSet( cmdBegin, SPACE_AND_TAB ); assert( cmdBegin != cmdEnd ); const char * const paramBegin = SkipCharsInSet( cmdEnd, SPACE_AND_TAB ); bool extraParamsFound = false; if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_QUESTION_MARK, true, false, &extraParamsFound ) || IsCmd( cmdBegin, cmdEnd, CMDNAME_HELP, false, false, &extraParamsFound ) ) { PrintStr( "This console is similar to the Bus Pirate console." EOL ); PrintStr( "Commands longer than 1 character are case insensitive." EOL ); PrintStr( "WARNING: If a command takes too long to run, the watchdog may reset the board." EOL ); PrintStr( "Commands are:" EOL ); Printf( " %s, %s: Show this help text." EOL, CMDNAME_QUESTION_MARK, CMDNAME_HELP ); Printf( " %s: Show version information." EOL, CMDNAME_I ); Printf( " %s: Test USB transfer speed." EOL, CMDNAME_USBSPEEDTEST ); Printf( " %s: Show JTAG pin status (read as inputs)." EOL, CMDNAME_JTAGPINS ); Printf( " %s: Test JTAG shift speed. WARNING: Do NOT connect any JTAG device." EOL, CMDNAME_JTAGSHIFTSPEEDTEST ); Printf( " %s: Exercises malloc()." EOL, CMDNAME_MALLOCTEST ); Printf( " %s: Exercises C++ exceptions." EOL, CMDNAME_CPP_EXCEPTION_TEST ); Printf( " %s: Shows memory usage." EOL, CMDNAME_MEMORY_USAGE ); Printf( " %s" EOL, CMDNAME_CPU_LOAD ); Printf( " %s" EOL, CMDNAME_UPTIME ); Printf( " %s" EOL, CMDNAME_RESET ); Printf( " %s" EOL, CMDNAME_RESET_CAUSE ); Printf( " %s <addr> <byte count>" EOL, CMDNAME_PRINT_MEMORY ); Printf( " %s <milliseconds>" EOL, CMDNAME_BUSY_WAIT ); Printf( " %s <command|protocol>" EOL, CMDNAME_SIMULATE_ERROR ); return; } if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_I, true, false, &extraParamsFound ) ) { #ifndef NDEBUG const char buildType[] = "Debug build"; #else const char buildType[] = "Release build"; #endif Printf( "JtagDue %s" EOL, PACKAGE_VERSION ); Printf( "%s, compiler version %s" EOL, buildType, __VERSION__ ); Printf( "Watchdog %s" EOL, ENABLE_WDT ? "enabled" : "disabled" ); return; } if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_RESET, false, false, &extraParamsFound ) ) { // This message does not reach the other side, we would need to add some delay. // UsbPrint( txBuffer, "Resetting the board..." EOL ); __disable_irq(); // Note that this message always goes to the serial port console, // even if the user is connected over USB. It might be possible to send // it over USB and then wait for the outgoing buffer to be empty. SerialSyncWriteStr( "Resetting the board..." EOL ); SerialWaitForDataSent(); ResetBoard( ENABLE_WDT ); assert( false ); // We should never reach this point. return; } if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_CPU_LOAD, false, false, &extraParamsFound ) ) { if ( ENABLE_CPU_SLEEP ) PrintStr( "CPU load statistics not available." EOL ); else DisplayCpuLoad(); return; } if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_UPTIME, false, false, &extraParamsFound ) ) { char buffer[ CONVERT_TO_DEC_BUF_SIZE ]; Printf( "Uptime: %s seconds." EOL, convert_unsigned_to_dec_th( GetUptime() / 1000, buffer, ',' ) ); return; } if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_RESET_CAUSE, false, false, &extraParamsFound ) ) { DisplayResetCause(); return; } if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_PRINT_MEMORY, false, true, &extraParamsFound ) ) { PrintMemory( paramBegin ); return; } if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_BUSY_WAIT, false, true, &extraParamsFound ) ) { BusyWait( paramBegin ); return; } if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_USBSPEEDTEST, false, true, &extraParamsFound ) ) { ProcessUsbSpeedTestCmd( paramBegin, currentTime ); return; } if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_JTAGPINS, false, false, &extraParamsFound ) ) { PrintJtagPinStatus(); return; } if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_JTAGSHIFTSPEEDTEST, false, false, &extraParamsFound ) ) { if ( !IsNativeUsbPort() ) throw std::runtime_error( "This command is only available on the 'Native' USB port." ); // Fill the Rx buffer with some test data. assert( m_rxBuffer != NULL ); m_rxBuffer->Reset(); for ( uint32_t i = 0; !m_rxBuffer->IsFull(); ++i ) { m_rxBuffer->WriteElem( CUsbRxBuffer::ElemType( i ) ); } // If the mode is set to MODE_HIZ, you cannot see the generated signal with the oscilloscope. // Note also that the built-in pull-ups on the Atmel ATSAM3X8 are too weak (between 50 and 100 KOhm, // yields too slow a rising time) to be of any use. const bool oldPullUps = GetJtagPullups(); SetJtagPullups( false ); const JtagPinModeEnum oldMode = GetJtagPinMode(); SetJtagPinMode ( MODE_JTAG ); // Each JTAG transfer needs 2 bits in the Rx buffer, TMS and TDI, // but produces only 1 bit, TDO. const uint32_t jtagByteCount = m_rxBuffer->GetElemCount() / 2; const uint16_t bitCount = jtagByteCount * 8; // Shift all JTAG data through several times. const uint64_t startTime = GetUptime(); const uint32_t iterCount = 50; for ( uint32_t i = 0; i < iterCount; ++i ) { // We hope that this will not clear the buffer contents. assert( m_rxBuffer != NULL ); assert( m_txBuffer != NULL ); m_rxBuffer->Reset(); m_rxBuffer->CommitWrittenElements( jtagByteCount * 2 ); m_txBuffer->Reset(); ShiftJtagData( m_rxBuffer, m_txBuffer, bitCount ); assert( m_txBuffer->GetElemCount() == jtagByteCount ); } const uint64_t finishTime = GetUptime(); const uint32_t elapsedTime = uint32_t( finishTime - startTime ); m_rxBuffer->Reset(); m_txBuffer->Reset(); const unsigned kBitsPerSec = unsigned( uint64_t(bitCount) * iterCount * 1000 / elapsedTime / 1024 ); SetJtagPinMode( oldMode ); SetJtagPullups( oldPullUps ); // I am getting 221 KiB/s with GCC 4.7.3 and optimisation level "-O3". Printf( EOL "Finished JTAG shift speed test, throughput %u Kbits/s (%u KiB/s)." EOL, kBitsPerSec, kBitsPerSec / 8 ); return; } if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_MALLOCTEST, false, false, &extraParamsFound ) ) { PrintStr( "Allocalling memory..." EOL ); volatile uint32_t * const volatile mallocTest = (volatile uint32_t *) malloc(123); *mallocTest = 123; PrintStr( "Releasing memory..." EOL ); free( const_cast< uint32_t * >( mallocTest ) ); PrintStr( "Test finished." EOL ); return; } if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_CPP_EXCEPTION_TEST, false, false, &extraParamsFound ) ) { try { PrintStr( "Throwing integer exception..." EOL ); throw 123; PrintStr( "Throw did not work." EOL ); assert( false ); } catch ( ... ) { PrintStr( "Caught integer exception." EOL ); } PrintStr( "Test finished." EOL ); return; } if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_SIMULATE_ERROR, false, true, &extraParamsFound ) ) { SimulateError( paramBegin ); return; } if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_MEMORY_USAGE, false, false, &extraParamsFound ) ) { const unsigned heapSize = unsigned( GetHeapEndAddr() - uintptr_t( &_end ) ); Printf( "Partitions: malloc heap: %u bytes, free: %u bytes, stack: %u bytes." EOL, heapSize, GetStackStartAddr() - GetHeapEndAddr(), STACK_SIZE ); Printf( "Used stack (estimated): %u from %u bytes." EOL, unsigned( GetStackSizeUsageEstimate() ), STACK_SIZE ); const struct mallinfo mi = mallinfo(); const unsigned heapSizeAccordingToNewlib = unsigned( mi.arena ); Printf( "Heap: %u allocated from %u bytes." EOL, unsigned( mi.uordblks ), unsigned( mi.arena ) ); assert( heapSize == heapSizeAccordingToNewlib ); UNUSED_IN_RELEASE( heapSizeAccordingToNewlib ); return; } if ( extraParamsFound ) Printf( "Command \"%.*s\" does not take any parameters." EOL, cmdEnd - cmdBegin, cmdBegin ); else Printf( "Unknown command \"%.*s\"." EOL, cmdEnd - cmdBegin, cmdBegin ); }