tFlexPALrc FlexPALDevice::deviceInfo( uint32 *pnModel, uint32 *pnSerialNr ) { tFlexPALrc nRC = FLEXPAL_SUCCESS; nRC = readOp( RDAL_OP_GET_MODEL, 0, 0, &mModel ); if( nRC != FLEXPAL_SUCCESS ) { // TODO: Set Error Info goto DEVICE_INFO_EXIT; } *pnModel = mModel; nRC = readOp( RDAL_OP_GET_SERIAL_NUM, 0, 0, &mSerialNr ); if( nRC != FLEXPAL_SUCCESS ) { // TODO: Set Error Info goto DEVICE_INFO_EXIT; } *pnSerialNr = this->mSerialNr; DEVICE_INFO_EXIT: return nRC; }
memhandle Enc28J60Network::receivePacket() { uint8_t rxstat; uint16_t len; // check if a packet has been received and buffered //if( !(readReg(EIR) & EIR_PKTIF) ){ // The above does not work. See Rev. B4 Silicon Errata point 6. if (readReg(EPKTCNT) != 0) { uint16_t readPtr = nextPacketPtr+6 > RXSTOP_INIT ? nextPacketPtr+6-RXSTOP_INIT+RXSTART_INIT : nextPacketPtr+6; // Set the read pointer to the start of the received packet writeRegPair(ERDPTL, nextPacketPtr); // read the next packet pointer nextPacketPtr = readOp(ENC28J60_READ_BUF_MEM, 0); nextPacketPtr |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; // read the packet length (see datasheet page 43) len = readOp(ENC28J60_READ_BUF_MEM, 0); len |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; len -= 4; //remove the CRC count // read the receive status (see datasheet page 43) rxstat = readOp(ENC28J60_READ_BUF_MEM, 0); //rxstat |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; #ifdef ENC28J60DEBUG Serial.print("receivePacket ["); Serial.print(readPtr,HEX); Serial.print("-"); Serial.print((readPtr+len) % (RXSTOP_INIT+1),HEX); Serial.print("], next: "); Serial.print(nextPacketPtr,HEX); Serial.print(", stat: "); Serial.print(rxstat,HEX); Serial.print(", count: "); Serial.print(readReg(EPKTCNT)); Serial.print(" -> "); Serial.println((rxstat & 0x80)!=0 ? "OK" : "failed"); #endif // decrement the packet counter indicate we are done with this packet writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC); // check CRC and symbol errors (see datasheet page 44, table 7-3): // The ERXFCON.CRCEN is set by default. Normally we should not // need to check this. if ((rxstat & 0x80) != 0) { receivePkt.begin = readPtr; receivePkt.size = len; #ifdef ENC28J60DEBUG Serial.print("receivePkt.size="); Serial.println(len); #endif return UIP_RECEIVEBUFFERHANDLE; } // Move the RX read pointer to the start of the next received packet // This frees the memory we just read out setERXRDPT(); } return (NOBLOCK); }
void CompilationEngine::compileExpression() { /* term (op term)* */ tagNonTerminal("expression"); compileTerm(); while (jt.tokenType() == TokenType::kSYMBOL && isOp(jt.symbol())) { readOp(); nextToken(); compileTerm(); } untagNonTerminal("expression"); }
void Enc28J60Network::memblock_mv_cb(uint16_t dest, uint16_t src, uint16_t len) { //as ENC28J60 DMA is unable to copy single bytes: if (len == 1) { writeByte(dest,readByte(src)); } else { // calculate address of last byte len += src - 1; /* 1. Appropriately program the EDMAST, EDMAND and EDMADST register pairs. The EDMAST registers should point to the first byte to copy from, the EDMAND registers should point to the last byte to copy and the EDMADST registers should point to the first byte in the destination range. The destination range will always be linear, never wrapping at any values except from 8191 to 0 (the 8-Kbyte memory boundary). Extreme care should be taken when programming the start and end pointers to prevent a never ending DMA operation which would overwrite the entire 8-Kbyte buffer. */ writeRegPair(EDMASTL, src); writeRegPair(EDMADSTL, dest); if ((src <= RXSTOP_INIT)&& (len > RXSTOP_INIT))len -= (RXSTOP_INIT-RXSTART_INIT); writeRegPair(EDMANDL, len); /* 2. If an interrupt at the end of the copy process is desired, set EIE.DMAIE and EIE.INTIE and clear EIR.DMAIF. 3. Verify that ECON1.CSUMEN is clear. */ writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_CSUMEN); /* 4. Start the DMA copy by setting ECON1.DMAST. */ writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST); // wait until runnig DMA is completed while (readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST); } }
static asynStatus readOpOnce(const char *port, int addr, epicsFloat64 *pvalue,double timeout,const char *drvInfo) { asynStatus status; asynUser *pasynUser; status = connect(port,addr,&pasynUser,drvInfo); if(status!=asynSuccess) { asynPrint(pasynUser, ASYN_TRACE_ERROR, "asynFloat64SyncIO connect failed %s\n", pasynUser->errorMessage); disconnect(pasynUser); return status; } status = readOp(pasynUser,pvalue,timeout); if(status!=asynSuccess) { asynPrint(pasynUser, ASYN_TRACE_ERROR, "asynFloat64SyncIO readOp failed %s\n",pasynUser->errorMessage); } disconnect(pasynUser); return status; }
memhandle Enc28J60Network::receivePacket() { uint16_t rxstat; uint16_t len; // check if a packet has been received and buffered //if( !(readReg(EIR) & EIR_PKTIF) ){ // The above does not work. See Rev. B4 Silicon Errata point 6. if (readReg(EPKTCNT) != 0) { readPtr = nextPacketPtr+6; // Set the read pointer to the start of the received packet writeReg(ERDPTL, (nextPacketPtr)); writeOp(ENC28J60_WRITE_CTRL_REG, ERDPTH, (nextPacketPtr) >> 8); // read the next packet pointer nextPacketPtr = readOp(ENC28J60_READ_BUF_MEM, 0); nextPacketPtr |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; // read the packet length (see datasheet page 43) len = readOp(ENC28J60_READ_BUF_MEM, 0); len |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; len -= 4; //remove the CRC count // read the receive status (see datasheet page 43) rxstat = readOp(ENC28J60_READ_BUF_MEM, 0); rxstat |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; // decrement the packet counter indicate we are done with this packet writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC); // check CRC and symbol errors (see datasheet page 44, table 7-3): // The ERXFCON.CRCEN is set by default. Normally we should not // need to check this. if ((rxstat & 0x80) != 0) { receivePkt.begin = readPtr; receivePkt.size = len; return UIP_RECEIVEBUFFERHANDLE; } // Move the RX read pointer to the start of the next received packet // This frees the memory we just read out writeReg(ERXRDPTL, (nextPacketPtr)); writeReg(ERXRDPTH, (nextPacketPtr) >> 8); }
osg::Image* readRaw(int sizeX, int sizeY, int sizeZ, int numberBytesPerComponent, int numberOfComponents, const std::string& endian, const std::string& raw_filename) { osgDB::ifstream fin(raw_filename.c_str(), std::ifstream::binary); if (!fin) return 0; GLenum pixelFormat; switch(numberOfComponents) { case 1 : pixelFormat = GL_LUMINANCE; break; case 2 : pixelFormat = GL_LUMINANCE_ALPHA; break; case 3 : pixelFormat = GL_RGB; break; case 4 : pixelFormat = GL_RGBA; break; default : osg::notify(osg::NOTICE)<<"Error: numberOfComponents="<<numberOfComponents<<" not supported, only 1,2,3 or 4 are supported."<<std::endl; return 0; } GLenum dataType; switch(numberBytesPerComponent) { case 1 : dataType = GL_UNSIGNED_BYTE; break; case 2 : dataType = GL_UNSIGNED_SHORT; break; case 4 : dataType = GL_UNSIGNED_INT; break; default : osg::notify(osg::NOTICE)<<"Error: numberBytesPerComponent="<<numberBytesPerComponent<<" not supported, only 1,2 or 4 are supported."<<std::endl; return 0; } int s_maximumTextureSize=256, t_maximumTextureSize=256, r_maximumTextureSize=256; int sizeS = sizeX; int sizeT = sizeY; int sizeR = sizeZ; clampToNearestValidPowerOfTwo(sizeS, sizeT, sizeR, s_maximumTextureSize, t_maximumTextureSize, r_maximumTextureSize); osg::ref_ptr<osg::Image> image = new osg::Image; image->allocateImage(sizeS, sizeT, sizeR, pixelFormat, dataType); bool endianSwap = (osg::getCpuByteOrder()==osg::BigEndian) ? (endian!="big") : (endian=="big"); unsigned int r_offset = (sizeZ<sizeR) ? sizeR/2 - sizeZ/2 : 0; int offset = endianSwap ? numberBytesPerComponent : 0; int delta = endianSwap ? -1 : 1; for(int r=0;r<sizeZ;++r) { for(int t=0;t<sizeY;++t) { char* data = (char*) image->data(0,t,r+r_offset); for(int s=0;s<sizeX;++s) { if (!fin) return 0; for(int c=0;c<numberOfComponents;++c) { char* ptr = data+offset; for(int b=0;b<numberBytesPerComponent;++b) { fin.read((char*)ptr, 1); ptr += delta; } data += numberBytesPerComponent; } } } } // normalise texture { // compute range of values osg::Vec4 minValue, maxValue; osg::computeMinMax(image.get(), minValue, maxValue); osg::modifyImage(image.get(),ScaleOperator(1.0f/maxValue.r())); } fin.close(); if (dataType!=GL_UNSIGNED_BYTE) { // need to convert to ubyte osg::ref_ptr<osg::Image> new_image = new osg::Image; new_image->allocateImage(sizeS, sizeT, sizeR, pixelFormat, GL_UNSIGNED_BYTE); RecordRowOperator readOp(sizeS); WriteRowOperator writeOp; for(int r=0;r<sizeR;++r) { for(int t=0;t<sizeT;++t) { // reset the indices to beginning readOp._pos = 0; writeOp._pos = 0; // read the pixels into readOp's _colour array osg::readRow(sizeS, pixelFormat, dataType, image->data(0,t,r), readOp); // pass readOp's _colour array contents over to writeOp (note this is just a pointer swap). writeOp._colours.swap(readOp._colours); osg::modifyRow(sizeS, pixelFormat, GL_UNSIGNED_BYTE, new_image->data(0,t,r), writeOp); // return readOp's _colour array contents back to its rightful owner. writeOp._colours.swap(readOp._colours); } } image = new_image; } return image.release(); }
bool copyImage(const osg::Image* srcImage, int src_s, int src_t, int src_r, int width, int height, int depth, osg::Image* destImage, int dest_s, int dest_t, int dest_r, bool doRescale) { if ((src_s+width) > (dest_s + destImage->s())) { OSG_NOTICE<<"copyImage("<<srcImage<<", "<<src_s<<", "<< src_t<<", "<<src_r<<", "<<width<<", "<<height<<", "<<depth<<std::endl; OSG_NOTICE<<" "<<destImage<<", "<<dest_s<<", "<< dest_t<<", "<<dest_r<<", "<<doRescale<<")"<<std::endl; OSG_NOTICE<<" input width too large."<<std::endl; return false; } if ((src_t+height) > (dest_t + destImage->t())) { OSG_NOTICE<<"copyImage("<<srcImage<<", "<<src_s<<", "<< src_t<<", "<<src_r<<", "<<width<<", "<<height<<", "<<depth<<std::endl; OSG_NOTICE<<" "<<destImage<<", "<<dest_s<<", "<< dest_t<<", "<<dest_r<<", "<<doRescale<<")"<<std::endl; OSG_NOTICE<<" input height too large."<<std::endl; return false; } if ((src_r+depth) > (dest_r + destImage->r())) { OSG_NOTICE<<"copyImage("<<srcImage<<", "<<src_s<<", "<< src_t<<", "<<src_r<<", "<<width<<", "<<height<<", "<<depth<<std::endl; OSG_NOTICE<<" "<<destImage<<", "<<dest_s<<", "<< dest_t<<", "<<dest_r<<", "<<doRescale<<")"<<std::endl; OSG_NOTICE<<" input depth too large."<<std::endl; return false; } float scale = 1.0f; if (doRescale && srcImage->getDataType() != destImage->getDataType()) { switch(srcImage->getDataType()) { case(GL_BYTE): scale = 1.0f/128.0f ; break; case(GL_UNSIGNED_BYTE): scale = 1.0f/255.0f; break; case(GL_SHORT): scale = 1.0f/32768.0f; break; case(GL_UNSIGNED_SHORT): scale = 1.0f/65535.0f; break; case(GL_INT): scale = 1.0f/2147483648.0f; break; case(GL_UNSIGNED_INT): scale = 1.0f/4294967295.0f; break; case(GL_FLOAT): scale = 1.0f; break; } switch(destImage->getDataType()) { case(GL_BYTE): scale *= 128.0f ; break; case(GL_UNSIGNED_BYTE): scale *= 255.0f; break; case(GL_SHORT): scale *= 32768.0f; break; case(GL_UNSIGNED_SHORT): scale *= 65535.0f; break; case(GL_INT): scale *= 2147483648.0f; break; case(GL_UNSIGNED_INT): scale *= 4294967295.0f; break; case(GL_FLOAT): scale *= 1.0f; break; } } if (srcImage->getPixelFormat() == destImage->getPixelFormat()) { //OSG_NOTICE<<"copyImage("<<srcImage<<", "<<src_s<<", "<< src_t<<", "<<src_r<<", "<<width<<", "<<height<<", "<<depth<<std::endl; //OSG_NOTICE<<" "<<destImage<<", "<<dest_s<<", "<< dest_t<<", "<<dest_r<<", "<<doRescale<<")"<<std::endl; if (srcImage->getDataType() == destImage->getDataType() && !doRescale) { //OSG_NOTICE<<" Compatible pixelFormat and dataType."<<std::endl; for(int slice = 0; slice<depth; ++slice) { for(int row = 0; row<height; ++row) { const unsigned char* srcData = srcImage->data(src_s, src_t+row, src_r+slice); unsigned char* destData = destImage->data(dest_s, dest_t+row, dest_r+slice); memcpy(destData, srcData, (width*destImage->getPixelSizeInBits())/8); } } return true; } else { //OSG_NOTICE<<" Compatible pixelFormat and incompatible dataType."<<std::endl; for(int slice = 0; slice<depth; ++slice) { for(int row = 0; row<height; ++row) { const unsigned char* srcData = srcImage->data(src_s, src_t+row, src_r+slice); unsigned char* destData = destImage->data(dest_s, dest_t+row, dest_r+slice); unsigned int numComponents = osg::Image::computeNumComponents(destImage->getPixelFormat()); _copyRowAndScale(srcData, srcImage->getDataType(), destData, destImage->getDataType(), (width*numComponents), scale); } } return true; } } else { //OSG_NOTICE<<"copyImage("<<srcImage<<", "<<src_s<<", "<< src_t<<", "<<src_r<<", "<<width<<", "<<height<<", "<<depth<<std::endl; //OSG_NOTICE<<" "<<destImage<<", "<<dest_s<<", "<< dest_t<<", "<<dest_r<<", "<<doRescale<<")"<<std::endl; RecordRowOperator readOp(width); WriteRowOperator writeOp; for(int slice = 0; slice<depth; ++slice) { for(int row = 0; row<height; ++row) { // reset the indices to beginning readOp._pos = 0; writeOp._pos = 0; // read the pixels into readOp's _colour array readRow(width, srcImage->getPixelFormat(), srcImage->getDataType(), srcImage->data(src_s,src_t+row,src_r+slice), readOp); // pass readOp's _colour array contents over to writeOp (note this is just a pointer swap). writeOp._colours.swap(readOp._colours); modifyRow(width, destImage->getPixelFormat(), destImage->getDataType(), destImage->data(dest_s, dest_t+row,dest_r+slice), writeOp); // return readOp's _colour array contents back to its rightful owner. writeOp._colours.swap(readOp._colours); } } return false; } }
void Enc28J60Network::init(uint8_t* macaddr) { MemoryPool::init(); // 1 byte in between RX_STOP_INIT and pool to allow prepending of controlbyte // initialize I/O // ss as output: pinMode(ENC28J60_CONTROL_CS, OUTPUT); CSPASSIVE; // ss=0 // #ifdef ENC28J60DEBUG Serial.println("ENC28J60::initialize / before initSPI()"); #endif SPI.begin(); SPI.setBitOrder(MSBFIRST); // SPI.setDataMode(SPI_MODE0); // SPI.setClockDivider(SPI_CLOCK_DIV16); #ifdef ENC28J60DEBUG Serial.println("ENC28J60::initialize / after initSPI()"); Serial.print("ENC28J60::initialize / csPin = "); Serial.println(SPI.nssPin()); Serial.print("ENC28J60::initialize / miso = "); Serial.println(SPI.misoPin()); Serial.print("ENC28J60::initialize / mosi = "); Serial.println(SPI.mosiPin()); Serial.print("ENC28J60::initialize / sck = "); Serial.println(SPI.sckPin()); #endif selectPin = ENC28J60_CONTROL_CS; pinMode(selectPin, OUTPUT); digitalWrite(selectPin, HIGH); // perform system reset writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); delay(2); // errata B7/2 delay(50); // check CLKRDY bit to see if reset is complete // The CLKRDY does not work. See Rev. B4 Silicon Errata point. Just wait. //while(!(readReg(ESTAT) & ESTAT_CLKRDY)); // do bank 0 stuff // initialize receive buffer // 16-bit transfers, must write low byte first // set receive buffer start address #ifdef ENC28J60DEBUG Serial.println("ENC28J60::initialize / before readOp(ENC28J60_READ_CTRL_REG, ESTAT)"); #endif while (!readOp(ENC28J60_READ_CTRL_REG, ESTAT) & ESTAT_CLKRDY) ; #ifdef ENC28J60DEBUG Serial.println("ENC28J60::initialize / after readOp(ENC28J60_READ_CTRL_REG, ESTAT)"); #endif nextPacketPtr = RXSTART_INIT; // Rx start writeRegPair(ERXSTL, RXSTART_INIT); // set receive pointer address writeRegPair(ERXRDPTL, RXSTART_INIT); // RX end writeRegPair(ERXNDL, RXSTOP_INIT); // TX start //-------------writeRegPair(ETXSTL, TXSTART_INIT); // TX end //-------------writeRegPair(ETXNDL, TXSTOP_INIT); // do bank 1 stuff, packet filter: // For broadcast packets we allow only ARP packtets // All other packets should be unicast only for our mac (MAADR) // // The pattern to match on is therefore // Type ETH.DST // ARP BROADCAST // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9 // in binary these poitions are:11 0000 0011 1111 // This is hex 303F->EPMM0=0x3f,EPMM1=0x30 //TODO define specific pattern to receive dhcp-broadcast packages instead of setting ERFCON_BCEN! // enableBroadcast(); // change to add ERXFCON_BCEN recommended by epam writeReg(ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN|ERXFCON_BCEN); writeRegPair(EPMM0, 0x303f); writeRegPair(EPMCSL, 0xf7f9); // // // do bank 2 stuff // enable MAC receive // and bring MAC out of reset (writes 0x00 to MACON2) writeRegPair(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS); //----------------writeRegPair(MACON2, 0x00); // enable automatic padding to 60bytes and CRC operations writeOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN); // set inter-frame gap (non-back-to-back) writeRegPair(MAIPGL, 0x0C12); // set inter-frame gap (back-to-back) writeReg(MABBIPG, 0x12); // Set the maximum packet size which the controller will accept // Do not send packets longer than MAX_FRAMELEN: writeRegPair(MAMXFLL, MAX_FRAMELEN); // do bank 3 stuff // write MAC address // NOTE: MAC address in ENC28J60 is byte-backward writeReg(MAADR5, macaddr[0]); writeReg(MAADR4, macaddr[1]); writeReg(MAADR3, macaddr[2]); writeReg(MAADR2, macaddr[3]); writeReg(MAADR1, macaddr[4]); writeReg(MAADR0, macaddr[5]); // no loopback of transmitted frames phyWrite(PHCON2, PHCON2_HDLDIS); // switch to bank 0 setBank(ECON1); // enable interrutps writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE); // enable packet reception writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); //Configure leds phyWrite(PHLCON,0x476); byte rev = readReg(EREVID); // microchip forgot to step the number on the silcon when they // released the revision B7. 6 is now rev B7. We still have // to see what they do when they release B8. At the moment // there is no B8 out yet if (rev > 5) ++rev; #ifdef ENC28J60DEBUG Serial.print("ENC28J60::initialize returns "); Serial.println(rev); #endif // return rev; }
byte Enc28J60Network::readRegByte (uint8_t address) { setBank(address); return readOp(ENC28J60_READ_CTRL_REG, address); }
/* ======================================================================= */ ENC28J60Driver::ENC28J60Driver(uint8_t* macaddr, uint8_t csPin): EthernetDriver(macaddr){ this->sendBuffer = new ENC28J60Buffer(this,TXSTART_INIT+1, TXSTOP_INIT, MAX_FRAMELEN, 0,false); this->recvBuffer = new ENC28J60Buffer(this,RXSTART_INIT, RXSTOP_INIT, MAX_FRAMELEN, 0,true); this->stashBuffer = new ENC28J60Buffer(this,STASH_START_INIT, STASH_STOP_INIT, STASH_STOP_INIT - STASH_START_INIT +1, 0,false); if (bitRead(SPCR, SPE) == 0) initSPI(); selectPin = csPin; pinMode(selectPin, OUTPUT); disableChip(); writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); delay(2); // errata B7/2 while (!readOp(ENC28J60_READ_CTRL_REG, ESTAT) & ESTAT_CLKRDY) ; gNextPacketPtr = RXSTART_INIT; writeReg(ERXST, RXSTART_INIT); writeReg(ERXRDPT, RXSTART_INIT); writeReg(ERXND, RXSTOP_INIT); writeReg(ETXST, TXSTART_INIT); writeReg(ETXND, TXSTOP_INIT); writeRegByte(ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN|ERXFCON_BCEN); writeReg(EPMM0, 0x303f); writeReg(EPMCS, 0xf7f9); writeRegByte(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS); writeRegByte(MACON2, 0x00); writeOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN); writeReg(MAIPG, 0x0C12); writeRegByte(MABBIPG, 0x12); writeReg(MAMXFL, MAX_FRAMELEN); writeRegByte(MAADR5, macaddr[0]); writeRegByte(MAADR4, macaddr[1]); writeRegByte(MAADR3, macaddr[2]); writeRegByte(MAADR2, macaddr[3]); writeRegByte(MAADR1, macaddr[4]); writeRegByte(MAADR0, macaddr[5]); writePhy(PHCON2, PHCON2_HDLDIS); SetBank(ECON1); writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE); writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); this->revision = readRegByte(EREVID); // microchip forgot to step the number on the silcon when they // released the revision B7. 6 is now rev B7. We still have // to see what they do when they release B8. At the moment // there is no B8 out yet if (this->revision > 5) this->revision++; }