Beispiel #1
0
        /// <summary> Read a Universal Data Packet.
        ///
        /// The Universal Data Packet always starts on page boundaries but
        /// can end anywhere in the page.  The structure specifies the length of
        /// data bytes not including the length byte and the CRC16 bytes.
        /// There is one length byte. The CRC16 is first initialized to
        /// the page number.  This provides a check to verify the page that
        /// was intended is being read.  The CRC16 is then calculated over
        /// the length and data bytes.  The CRC16 is then inverted and stored
        /// low byte first followed by the high byte.  This is structure is
        /// used by this method to verify the data but is not returned, only
        /// the data payload is returned.
        ///
        /// </summary>
        /// <param name="page">         page number to read packet from
        /// </param>
        /// <param name="readContinue"> if 'true' then device read is continued without
        /// re-selecting.  This can only be used if the new
        /// readPagePacket() continious where the last one
        /// stopped and it is inside a
        /// 'beginExclusive/endExclusive' block.
        /// </param>
        /// <param name="readBuf">      byte array to put data read. Must have at least
        /// 'getMaxPacketDataLength()' elements.
        /// </param>
        /// <param name="offset">       offset into readBuf to place data
        ///
        /// </param>
        /// <returns>  number of data bytes read from the device and written to
        /// readBuf at the offset.
        ///
        /// </returns>
        /// <throws>  OneWireIOException </throws>
        /// <throws>  OneWireException </throws>
        public virtual int readPagePacket(int page, bool readContinue, byte[] readBuf, int offset)
        {
            byte[] raw_buf = new byte[PAGE_LENGTH];

            // attempt to put device at speed
            checkSpeed();

            // read the scratchpad, discard extra information
            readPage(page, readContinue, raw_buf, 0);

            // check if length is realistic
            if (raw_buf[0] > (PAGE_LENGTH - 3))
            {
                forceVerify();

                throw new OneWireIOException("Invalid length in packet");
            }

            // verify the CRC is correct
            if (CRC16.compute(raw_buf, 0, raw_buf[0] + 3, page) == 0x0000B001)
            {
                // extract the data out of the packet
                Array.Copy(raw_buf, 1, readBuf, offset, (byte)raw_buf[0]);

                // return the length
                return(raw_buf[0]);
            }
            else
            {
                forceVerify();

                throw new OneWireIOException("Invalid CRC16 in packet read");
            }
        }
Beispiel #2
0
        /// <summary> Read a Universal Data Packet and extra information.  See the
        /// method 'readPagePacket()' for a description of the packet structure.
        /// See the method 'hasExtraInfo()' for a description of the optional
        /// extra information some devices have.
        ///
        /// </summary>
        /// <param name="page">         page number to read packet from
        /// </param>
        /// <param name="readContinue"> if 'true' then device read is continued without
        /// re-selecting.  This can only be used if the new
        /// readPagePacket() continious where the last one
        /// stopped and it is inside a
        /// 'beginExclusive/endExclusive' block.
        /// </param>
        /// <param name="readBuf">      byte array to put data read. Must have at least
        /// 'getMaxPacketDataLength()' elements.
        /// </param>
        /// <param name="offset">       offset into readBuf to place data
        /// </param>
        /// <param name="extraInfo">    byte array to put extra info read into
        ///
        /// </param>
        /// <returns>  number of data bytes written to readBuf at the offset.
        ///
        /// </returns>
        /// <throws>  OneWireIOException </throws>
        /// <throws>  OneWireException </throws>
        public override int readPagePacket(int page, bool readContinue, byte[] readBuf, int offset, byte[] extraInfo)
        {
            byte[] raw_buf = new byte[pageLength];

            // read entire page with read page CRC
            readPageCRC(page, readContinue, raw_buf, 0, extraInfo, extraInfoLength);

            // check if length is realistic
            if (raw_buf[0] > maxPacketDataLength)
            {
                sp.forceVerify();

                throw new OneWireIOException("Invalid length in packet");
            }

            // verify the CRC is correct
            int abs_page = (startPhysicalAddress / pageLength) + page;

            if (CRC16.compute(raw_buf, 0, raw_buf[0] + 3, abs_page) == 0x0000B001)
            {
                // extract the data out of the packet
                Array.Copy(raw_buf, 1, readBuf, offset, (byte)raw_buf[0]);

                // return the length
                return(raw_buf[0]);
            }
            else
            {
                sp.forceVerify();

                throw new OneWireIOException("Invalid CRC16 in packet read");
            }
        }
Beispiel #3
0
        //--------
        //-------- Information methods
        //--------

        //--------
        //-------- Custom Methods for this 1-Wire Device Type
        //--------

        /// <summary> Read the counter value associated with a page on this
        /// 1-Wire Device.
        ///
        /// </summary>
        /// <param name="counterPage">   page number of the counter to read
        ///
        /// </param>
        /// <returns>  4 byte value counter stored in a long integer
        ///
        /// </returns>
        /// <throws>  OneWireIOException on a 1-Wire communication error such as  </throws>
        /// <summary>         no 1-Wire device present.  This could be
        /// caused by a physical interruption in the 1-Wire Network due to
        /// shorts or a newly arriving 1-Wire device issuing a 'presence pulse'.
        /// </summary>
        /// <throws>  OneWireException on a communication or setup error with the 1-Wire  </throws>
        /// <summary>         adapter
        /// </summary>
        public virtual long readCounter(int counterPage)
        {
            // check if counter page provided is valid
            if ((counterPage < 12) || (counterPage > 15))
            {
                throw new OneWireException("OneWireContainer1D-invalid counter page");
            }

            // select the device
            if (adapter.select(this.address))
            {
                int crc16;

                // read memory command
                buffer[0] = READ_MEMORY_COMMAND;
                crc16     = CRC16.compute(READ_MEMORY_COMMAND);

                // address of last data byte before counter
                int address = (counterPage << 5) + 31;

                // append the address
                buffer[1] = (byte)address;
                crc16     = CRC16.compute(buffer[1], crc16);
                buffer[2] = (byte)(SupportClass.URShift(address, 8));
                crc16     = CRC16.compute(buffer[2], crc16);

                // now add the read bytes for data byte,counter,zero bits, crc16
                for (int i = 3; i < 14; i++)
                {
                    buffer[i] = (byte)SupportClass.Identity(0xFF);
                }

                // send the block
                adapter.dataBlock(buffer, 0, 14);

                // calculate the CRC16 on the result and check if correct
                if (CRC16.compute(buffer, 3, 11, crc16) == 0xB001)
                {
                    // extract the counter out of this verified packet
                    ulong return_count = 0;

                    for (int i = 4; i >= 1; i--)
                    {
                        return_count <<= 8;
                        return_count  |= (byte)(buffer[i + 3] & (byte)0xFF);
                    }

                    // return the result count
                    return((long)return_count);
                }
            }

            // device must not have been present
            throw new OneWireIOException("OneWireContainer1D-device not present");
        }
Beispiel #4
0
        /// <summary> Read a complete memory page with CRC verification provided by the
        /// device.  Not supported by all devices.  See the method
        /// 'hasPageAutoCRC()'.
        ///
        /// </summary>
        /// <param name="page">         page number to read
        /// </param>
        /// <param name="readContinue"> if 'true' then device read is continued without
        /// re-selecting.  This can only be used if the new
        /// readPagePacket() continious where the last one
        /// stopped and it is inside a
        /// 'beginExclusive/endExclusive' block.
        /// </param>
        /// <param name="readBuf">      byte array to put data read. Must have at least
        /// 'getMaxPacketDataLength()' elements.
        /// </param>
        /// <param name="offset">       offset into readBuf to place data
        ///
        /// </param>
        /// <throws>  OneWireIOException </throws>
        /// <throws>  OneWireException </throws>
        public virtual void  readPageCRC(int page, bool readContinue, byte[] readBuf, int offset)
        {
            byte[] raw_buf = new byte[5 + PAGE_LENGTH];
            int    len;

            // attempt to put device at max desired speed
            if (!readContinue)
            {
                checkSpeed();
            }

            // see if need to access the device
            if (!readContinue)
            {
                // select the device
                if (!ib.adapter.select(ib.address))
                {
                    forceVerify();

                    throw new OneWireIOException("Device select failed");
                }

                // build start reading memory block with: command, address
                len = raw_buf.Length;

                Array.Copy(ffBlock, 0, raw_buf, 0, len);

                raw_buf[0] = READ_MEMORY_COMMAND;

                int addr = page * PAGE_LENGTH + startPhysicalAddress;

                raw_buf[1] = (byte)(addr & 0xFF);
                raw_buf[2] = (byte)((SupportClass.URShift((addr & 0xFFFF), 8)) & 0xFF);
            }
            else
            {
                len = PAGE_LENGTH + 2;

                Array.Copy(ffBlock, 0, raw_buf, 0, len);
            }

            // do the block
            ib.adapter.dataBlock(raw_buf, 0, len);

            // check the CRC
            if (CRC16.compute(raw_buf, 0, len, 0) != 0x0000B001)
            {
                forceVerify();

                throw new OneWireIOException("Invalid CRC16 read from device");
            }

            // extract the data to return
            Array.Copy(raw_buf, len - 2 - PAGE_LENGTH, readBuf, offset, PAGE_LENGTH);
        }
        //--------
        //-------- ScratchPad methods
        //--------

        /// <summary> Write to the scratchpad page of memory a NVRAM device.
        ///
        /// </summary>
        /// <param name="startAddr">    starting address
        /// </param>
        /// <param name="writeBuf">     byte array containing data to write
        /// </param>
        /// <param name="offset">       offset into readBuf to place data
        /// </param>
        /// <param name="len">          length in bytes to write
        ///
        /// </param>
        /// <throws>  OneWireIOException </throws>
        /// <throws>  OneWireException </throws>
        public override void  writeScratchpad(int startAddr, byte[] writeBuf, int offset, int len)
        {
            bool calcCRC = false;

            if (len > pageLength)
            {
                throw new OneWireException("Write exceeds memory bank end");
            }

            // select the device
            if (!ib.adapter.select(ib.address))
            {
                forceVerify();

                throw new OneWireIOException("Device select failed");
            }

            // build block to send
            byte[] raw_buf = new byte[pageLength + 5];             //[37];

            raw_buf[0] = WRITE_SCRATCHPAD_COMMAND;
            raw_buf[1] = (byte)(startAddr & 0xFF);
            raw_buf[2] = (byte)((SupportClass.URShift((startAddr & 0xFFFF), 8)) & 0xFF);

            Array.Copy(writeBuf, offset, raw_buf, 3, len);

            // check if full page (can utilize CRC)
            if (((startAddr + len) % pageLength) == 0)
            {
                Array.Copy(ffBlock, 0, raw_buf, len + 3, 2);

                calcCRC = true;
            }

            // send block, return result
            ib.adapter.dataBlock(raw_buf, 0, len + 3 + ((calcCRC)?2:0));
            //System.out.println("WriteScratchpad: " + com.dalsemi.onewire.utils.Convert.toHexString(raw_buf));

            // check crc
            if (calcCRC)
            {
                if (CRC16.compute(raw_buf, 0, len + 5, 0) != 0x0000B001)
                {
                    forceVerify();

                    throw new OneWireIOException("Invalid CRC16 read from device");
                }
            }
        }
Beispiel #6
0
        //--------
        //-------- ScratchPad methods
        //--------

        /// <summary> Read the scratchpad page of memory from a NVRAM device
        /// This method reads and returns the entire scratchpad after the byte
        /// offset regardless of the actual ending offset
        ///
        /// </summary>
        /// <param name="readBuf">      byte array to place read data into
        /// length of array is always pageLength.
        /// </param>
        /// <param name="offset">       offset into readBuf to pug data
        /// </param>
        /// <param name="len">          length in bytes to read
        /// </param>
        /// <param name="extraInfo">    byte array to put extra info read into
        /// (TA1, TA2, e/s byte)
        /// length of array is always extraInfoLength.
        /// Can be 'null' if extra info is not needed.
        ///
        /// </param>
        /// <throws>  OneWireIOException </throws>
        /// <throws>  OneWireException </throws>
        public override void  readScratchpad(byte[] readBuf, int offset, int len, byte[] extraInfo)
        {
            // select the device
            if (!ib.adapter.select(ib.address))
            {
                forceVerify();

                throw new OneWireIOException("Device select failed");
            }

            // build block
            byte[] raw_buf = new byte[extraInfoLength + pageLength + 3];

            raw_buf[0] = READ_SCRATCHPAD_COMMAND;

            Array.Copy(ffBlock, 0, raw_buf, 1, raw_buf.Length - 1);

            // send block, command + (extra) + page data + CRC
            ib.adapter.dataBlock(raw_buf, 0, raw_buf.Length);

            // get the starting offset to see when the crc will show up
            int addr = raw_buf[1];

            addr = (addr | ((raw_buf[2] << 8) & 0xFF00)) & 0xFFFF;

            int num_crc = 35 - (addr & 0x001F) + extraInfoLength;

            // check crc of entire block
            if (CRC16.compute(raw_buf, 0, num_crc, 0) != 0x0000B001)
            {
                forceVerify();

                throw new OneWireIOException("Invalid CRC16 read from device");
            }

            // optionally extract the extra info
            if (extraInfo != null)
            {
                Array.Copy(raw_buf, 1, extraInfo, 0, extraInfoLength);
            }

            // extract the page data
            Array.Copy(raw_buf, extraInfoLength + 1, readBuf, 0, pageLength);
        }
Beispiel #7
0
        /// <summary> Write a Universal Data Packet.  See the method 'readPagePacket()'
        /// for a description of the packet structure.
        ///
        /// </summary>
        /// <param name="page">         page number to write packet to
        /// </param>
        /// <param name="writeBuf">     data byte array to write
        /// </param>
        /// <param name="offset">       offset into writeBuf where data to write is
        /// </param>
        /// <param name="len">          number of bytes to write
        ///
        /// </param>
        /// <throws>  OneWireIOException </throws>
        /// <throws>  OneWireException </throws>
        public virtual void  writePagePacket(int page, byte[] writeBuf, int offset, int len)
        {
            // make sure length does not exceed max
            if (len > (PAGE_LENGTH - 3))
            {
                throw new OneWireIOException("Length of packet requested exceeds page size");
            }

            // construct the packet to write
            byte[] raw_buf = new byte[len + 3];

            raw_buf[0] = (byte)len;

            Array.Copy(writeBuf, offset, raw_buf, 1, len);

            int crc = CRC16.compute(raw_buf, 0, len + 1, page);

            raw_buf[len + 1] = (byte)(~crc & 0xFF);
            raw_buf[len + 2] = (byte)((SupportClass.URShift((~crc & 0xFFFF), 8)) & 0xFF);

            // write the packet, return result
            write(page * PAGE_LENGTH, raw_buf, 0, len + 3);
        }
Beispiel #8
0
        /// <summary> Read a complete memory page with CRC verification provided by the
        /// device with extra information.  Not supported by all devices.
        /// If not extra information available then just call with extraLength=0.
        ///
        /// </summary>
        /// <param name="page">         page number to read
        /// </param>
        /// <param name="readContinue"> if 'true' then device read is continued without
        /// re-selecting.  This can only be used if the new
        /// readPagePacket() continious where the last one
        /// stopped and it is inside a
        /// 'beginExclusive/endExclusive' block.
        /// </param>
        /// <param name="readBuf">      byte array to put data read. Must have at least
        /// 'getMaxPacketDataLength()' elements.
        /// </param>
        /// <param name="offset">       offset into readBuf to place data
        /// </param>
        /// <param name="extraInfo">    byte array to put extra info read into
        /// </param>
        /// <param name="extraLength">  length of extra information
        ///
        /// </param>
        /// <throws>  OneWireIOException </throws>
        /// <throws>  OneWireException </throws>
        protected internal virtual void  readPageCRC(int page, bool readContinue, byte[] readBuf, int offset, byte[] extraInfo, int extraLength)
        {
            int last_crc = 0;

            byte[] raw_buf;

            // only needs to be implemented if supported by hardware
            if (!pageAutoCRC)
            {
                throw new OneWireException("Read page with CRC not supported in this memory bank");
            }

            // attempt to put device at max desired speed
            if (!readContinue)
            {
                sp.checkSpeed();
            }

            // check if read exceeds memory
            if (page > numberPages)
            {
                throw new OneWireException("Read exceeds memory bank end");
            }

            // see if need to access the device
            if (!readContinue || !readContinuePossible)
            {
                // select the device
                if (!ib.adapter.select(ib.address))
                {
                    sp.forceVerify();

                    throw new OneWireIOException("Device select failed");
                }

                // build start reading memory block
                raw_buf    = new byte[3];
                raw_buf[0] = READ_PAGE_WITH_CRC;

                int addr = page * pageLength + startPhysicalAddress;

                raw_buf[1] = (byte)(addr & 0xFF);
                raw_buf[2] = (byte)((SupportClass.URShift((addr & 0xFFFF), 8)) & 0xFF);

                // perform CRC16 on first part
                last_crc = CRC16.compute(raw_buf, 0, raw_buf.Length, last_crc);

                // do the first block for command, TA1, TA2
                ib.adapter.dataBlock(raw_buf, 0, 3);
            }

            // pre-fill with 0xFF
            raw_buf = new byte[pageLength + extraLength + 2 + numVerifyBytes];

            Array.Copy(ffBlock, 0, raw_buf, 0, raw_buf.Length);

            // send block to read data + extra info? + crc
            ib.adapter.dataBlock(raw_buf, 0, raw_buf.Length);

            // check the CRC
            if (CRC16.compute(raw_buf, 0, raw_buf.Length - numVerifyBytes, last_crc) != 0x0000B001)
            {
                sp.forceVerify();

                throw new OneWireIOException("Invalid CRC16 read from device");
            }

            // extract the page data
            Array.Copy(raw_buf, 0, readBuf, offset, pageLength);

            // optional extract the extra info
            if (extraInfo != null)
            {
                Array.Copy(raw_buf, pageLength, extraInfo, 0, extraLength);
            }
        }
Beispiel #9
0
        /// <summary> Read a complete memory page with CRC verification provided by the
        /// device with extra information.  Not supported by all devices.
        /// If not extra information available then just call with extraLength=0.
        ///
        /// </summary>
        /// <param name="page">         page number to read
        /// </param>
        /// <param name="readContinue"> if 'true' then device read is continued without
        /// re-selecting.  This can only be used if the new
        /// readPagePacket() continious where the last one
        /// stopped and it is inside a
        /// 'beginExclusive/endExclusive' block.
        /// </param>
        /// <param name="readBuf">      byte array to put data read. Must have at least
        /// 'getMaxPacketDataLength()' elements.
        /// </param>
        /// <param name="offset">       offset into readBuf to place data
        /// </param>
        /// <param name="extraInfo">    byte array to put extra info read into
        /// </param>
        /// <param name="extraLength">  length of extra information
        ///
        /// </param>
        /// <throws>  OneWireIOException </throws>
        /// <throws>  OneWireException </throws>
        protected internal override void  readPageCRC(int page, bool readContinue, byte[] readBuf, int offset, byte[] extraInfo, int extraLength)
        {
            int last_crc = 0;

            byte[] raw_buf;
            byte   temp;

            // only needs to be implemented if supported by hardware
            if (!pageAutoCRC)
            {
                throw new OneWireException("Read page with CRC not supported in this memory bank");
            }

            // attempt to put device at max desired speed
            if (!readContinue)
            {
                sp.checkSpeed();
            }

            // check if read exceeds memory
            if (page > numberPages)
            {
                throw new OneWireException("Read exceeds memory bank end");
            }

            // see if need to access the device
            if (!readContinue || !readContinuePossible)
            {
                // select the device
                if (!ib.adapter.select(ib.address))
                {
                    sp.forceVerify();

                    throw new OneWireIOException("Device select failed");
                }

                // build start reading memory block
                raw_buf    = new byte[11];
                raw_buf[0] = READ_MEMORY_CRC_PW_COMMAND;

                int addr = page * pageLength + startPhysicalAddress;

                raw_buf[1] = (byte)(addr & 0xFF);
                raw_buf[2] = (byte)((SupportClass.URShift((addr & 0xFFFF), 8)) & 0xFF);

                if (ibPass.ContainerReadWritePasswordSet)
                {
                    ibPass.getContainerReadWritePassword(raw_buf, 3);
                }
                else
                {
                    ibPass.getContainerReadOnlyPassword(raw_buf, 3);
                }

                // perform CRC16 on first part (without the password)
                last_crc = CRC16.compute(raw_buf, 0, 3, last_crc);

                // do the first block for command, TA1, TA2, and password

                if (enablePower)
                {
                    ib.adapter.dataBlock(raw_buf, 0, 10);

                    ib.adapter.startPowerDelivery(DSPortAdapter.CONDITION_AFTER_BYTE);

                    ib.adapter.putByte(raw_buf[10]);
                }
                else
                {
                    ib.adapter.dataBlock(raw_buf, 0, 11);
                }
            }
            else
            {
                if (enablePower)
                {
                    ib.adapter.startPowerDelivery(DSPortAdapter.CONDITION_AFTER_BYTE);
                    temp = (byte)ib.adapter.Byte;
                }
            }

            if (enablePower)
            {
                msWait(3);

                ib.adapter.setPowerNormal();
            }

            // pre-fill with 0xFF
            raw_buf = new byte[pageLength + extraLength + 2 + numVerifyBytes];

            Array.Copy(ffBlock, 0, raw_buf, 0, raw_buf.Length);

            // send block to read data + extra info? + crc
            if (enablePower)
            {
                ib.adapter.dataBlock(raw_buf, 0, (raw_buf.Length - 1));
                last_crc = CRC16.compute(raw_buf, 0, raw_buf.Length - numVerifyBytes - 2, last_crc);

                if ((last_crc & 0x0FF) != ((~raw_buf[raw_buf.Length - 2]) & 0x0FF))
                {
                    sp.forceVerify();
                    throw new OneWireIOException("Invalid CRC16 read from device.  Password may be incorrect.");
                }
            }
            else
            {
                ib.adapter.dataBlock(raw_buf, 0, raw_buf.Length);

                // check the CRC
                if (CRC16.compute(raw_buf, 0, raw_buf.Length - numVerifyBytes, last_crc) != 0x0000B001)
                {
                    sp.forceVerify();
                    throw new OneWireIOException("Invalid CRC16 read from device.  Password may be incorrect.");
                }
            }

            // extract the page data
            Array.Copy(raw_buf, 0, readBuf, offset, pageLength);

            // optional extract the extra info
            if (extraInfo != null)
            {
                Array.Copy(raw_buf, pageLength, extraInfo, 0, extraLength);
            }
        }
Beispiel #10
0
        /// <summary> Write  memory in the current bank.  It is recommended that
        /// when writing  data that some structure in the data is created
        /// to provide error free reading back with read().  Or the
        /// method 'writePagePacket()' could be used which automatically
        /// wraps the data in a length and CRC.
        ///
        /// When using on Write-Once devices care must be taken to write into
        /// into empty space.  If write() is used to write over an unlocked
        /// page on a Write-Once device it will fail.  If write verification
        /// is turned off with the method 'setWriteVerification(false)' then
        /// the result will be an 'AND' of the existing data and the new data.
        ///
        /// </summary>
        /// <param name="startAddr">    starting address
        /// </param>
        /// <param name="writeBuf">     byte array containing data to write
        /// </param>
        /// <param name="offset">       offset into writeBuf to get data
        /// </param>
        /// <param name="len">          length in bytes to write
        ///
        /// </param>
        /// <throws>  OneWireIOException </throws>
        /// <throws>  OneWireException </throws>
        public virtual void  write(int startAddr, byte[] writeBuf, int offset, int len)
        {
            byte[] raw_buf = new byte[7];
            int    cnt = 0, start_addr, addr, end_addr, lastcrc;

            // return if nothing to do
            if (len == 0)
            {
                return;
            }

            // attempt to put device at max desired speed
            checkSpeed();

            // select the device
            if (!ib.adapter.select(ib.address))
            {
                forceVerify();

                throw new OneWireIOException("Device select failed");
            }

            // build packet
            raw_buf[cnt++] = WRITE_MEMORY_COMMAND;
            start_addr     = startAddr + startPhysicalAddress;
            end_addr       = start_addr + len;
            raw_buf[cnt++] = (byte)(start_addr & 0xFF);
            raw_buf[cnt++] = (byte)((SupportClass.URShift((start_addr & 0xFFFF), 8)) & 0xFF);

            // loop for each byte to write
            for (addr = start_addr; addr < end_addr; addr++)
            {
                // add the byte to write to buffer
                raw_buf[cnt++] = writeBuf[offset + addr - start_addr];

                // initialize crc16
                lastcrc = CRC16.compute(raw_buf, 0, cnt, (addr == start_addr)?0:addr);

                // add the read crc and echo byte to block
                Array.Copy(ffBlock, 0, raw_buf, cnt, 3);

                // perform the block
                ib.adapter.dataBlock(raw_buf, 0, cnt + 3);

                // check the CRC
                if (CRC16.compute(raw_buf, cnt, 2, lastcrc) != 0x0000B001)
                {
                    forceVerify();

                    throw new OneWireIOException("Invalid CRC16 read from device");
                }

                // check echo
                if (raw_buf[cnt + 2] != writeBuf[offset + addr - start_addr])
                {
                    forceVerify();

                    throw new OneWireIOException("Write byte echo was invalid");
                }

                // reset the buffer and loop
                cnt = 0;
            }
        }
        //--------
        //-------- ScratchPad methods
        //--------

        /// <summary> Write to the scratchpad page of memory a NVRAM device.
        ///
        /// </summary>
        /// <param name="startAddr">    starting address
        /// </param>
        /// <param name="writeBuf">     byte array containing data to write
        /// </param>
        /// <param name="offset">       offset into readBuf to place data
        /// </param>
        /// <param name="len">          length in bytes to write
        ///
        /// </param>
        /// <throws>  OneWireIOException </throws>
        /// <throws>  OneWireException </throws>
        public override void  writeScratchpad(int startAddr, byte[] writeBuf, int offset, int len)
        {
            bool calcCRC = false;

            byte[] raw_buf = new byte[37];

            // select the device
            if (!ib.adapter.select(ib.address))
            {
                forceVerify();

                throw new OneWireIOException("Device select failed");
            }

            // erase the scratchpad
            raw_buf[0] = ERASE_SCRATCHPAD_COMMAND;

            Array.Copy(ffBlock, 0, raw_buf, 1, 8);
            ib.adapter.dataBlock(raw_buf, 0, 9);

            if (((byte)(raw_buf[8] & 0x0F0) != (byte)SupportClass.Identity(0xA0)) && ((byte)(raw_buf[8] & 0x0F0) != (byte)0x50))
            {
                forceVerify();

                throw new OneWireIOException("Erase scratchpad complete not found");
            }

            // select the device
            if (!ib.adapter.select(ib.address))
            {
                forceVerify();

                throw new OneWireIOException("Device select failed");
            }

            // build block to send
            raw_buf[0] = WRITE_SCRATCHPAD_COMMAND;
            raw_buf[1] = (byte)(startAddr & 0xFF);
            raw_buf[2] = (byte)((SupportClass.URShift((startAddr & 0xFFFF), 8)) & 0xFF);

            Array.Copy(writeBuf, offset, raw_buf, 3, len);

            // check if full page (can utilize CRC)
            if (((startAddr + len) % pageLength) == 0)
            {
                Array.Copy(ffBlock, 0, raw_buf, len + 3, 2);

                calcCRC = true;
            }

            // send block, return result
            ib.adapter.dataBlock(raw_buf, 0, len + 3 + ((calcCRC)?2:0));

            // check crc
            if (calcCRC)
            {
                if (CRC16.compute(raw_buf, 0, len + 5, 0) != 0x0000B001)
                {
                    forceVerify();

                    throw new OneWireIOException("Invalid CRC16 read from device");
                }
            }
        }