// File: mrlordkaj[P]i2cdevlib-pi/I2Cdev/I2Cdev.cpp
// Function: I2Cdev::readBytes(unsigned char, unsigned char, unsigned char, unsigned char*, unsigned short)
int8_t I2Cdev::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout) {
    #ifdef I2CDEV_SERIAL_DEBUG
        Serial.print("I2C (0x");
        Serial.print(devAddr, HEX);
        Serial.print(") reading ");
        Serial.print(length, DEC);
        Serial.print(" bytes from 0x");
        Serial.print(regAddr, HEX);
        Serial.print("...");
    #endif

    int8_t count = 0;
    uint32_t t1 = millis();

    #if (I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE)

        #if (ARDUINO < 100)
            // Arduino v00xx (before v1.0), Wire library

            // I2C/TWI subsystem uses internal buffer that breaks with large data requests
            // so if user requests more than BUFFER_LENGTH bytes, we have to do it in
            // smaller chunks instead of all at once
            for (uint8_t k = 0; k < length; k += min((int)length, BUFFER_LENGTH)) {
                Wire.beginTransmission(devAddr);
                Wire.send(regAddr);
                Wire.endTransmission();
                Wire.beginTransmission(devAddr);
                Wire.requestFrom(devAddr, (uint8_t)min(length - k, BUFFER_LENGTH));

                for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) {
                    data[count] = Wire.receive();
                    #ifdef I2CDEV_SERIAL_DEBUG
                        Serial.print(data[count], HEX);
                        if (count + 1 < length) Serial.print(" ");
                    #endif
                }

                Wire.endTransmission();
            }
        #elif (ARDUINO == 100)
            // Arduino v1.0.0, Wire library
            // Adds standardized write() and read() stream methods instead of send() and receive()

            // I2C/TWI subsystem uses internal buffer that breaks with large data requests
            // so if user requests more than BUFFER_LENGTH bytes, we have to do it in
            // smaller chunks instead of all at once
            for (uint8_t k = 0; k < length; k += min((int)length, BUFFER_LENGTH)) {
                Wire.beginTransmission(devAddr);
                Wire.write(regAddr);
                Wire.endTransmission();
                Wire.beginTransmission(devAddr);
                Wire.requestFrom(devAddr, (uint8_t)min(length - k, BUFFER_LENGTH));
        
                for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) {
                    data[count] = Wire.read();
                    #ifdef I2CDEV_SERIAL_DEBUG
                        Serial.print(data[count], HEX);
                        if (count + 1 < length) Serial.print(" ");
                    #endif
                }
        
                Wire.endTransmission();
            }
        #elif (ARDUINO > 100)
            // Arduino v1.0.1+, Wire library
            // Adds official support for repeated start condition, yay!

            // I2C/TWI subsystem uses internal buffer that breaks with large data requests
            // so if user requests more than BUFFER_LENGTH bytes, we have to do it in
            // smaller chunks instead of all at once
            for (uint8_t k = 0; k < length; k += min((int)length, BUFFER_LENGTH)) {
                Wire.beginTransmission(devAddr);
                Wire.write(regAddr);
                Wire.endTransmission();
                Wire.beginTransmission(devAddr);
                Wire.requestFrom(devAddr, (uint8_t)min(length - k, BUFFER_LENGTH));
        
                for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) {
                    data[count] = Wire.read();
                    #ifdef I2CDEV_SERIAL_DEBUG
                        Serial.print(data[count], HEX);
                        if (count + 1 < length) Serial.print(" ");
                    #endif
                }
            }
        #endif

    #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE)

        // Fastwire library
        // no loop required for fastwire
        uint8_t status = Fastwire::readBuf(devAddr << 1, regAddr, data, length);
        if (status == 0) {
            count = length; // success
        } else {
            count = -1; // error
        }

    #endif

    // check for timeout
    if (timeout > 0 && millis() - t1 >= timeout && count < length) count = -1; // timeout

    #ifdef I2CDEV_SERIAL_DEBUG
        Serial.print(". Done (");
        Serial.print(count, DEC);
        Serial.println(" read).");
    #endif

    return count;
}

// Assembly:
subq $0x28, %rsp
movw %r8w, %ax
movb %dil, 0x27(%rsp)
movb %sil, 0x26(%rsp)
movb %dl, 0x25(%rsp)
movq %rcx, 0x18(%rsp)
movw %ax, 0x16(%rsp)
movb $0x0, 0x15(%rsp)
callq 0x22b10
movl %eax, 0x10(%rsp)
movb $0x0, 0xf(%rsp)
movzbl 0xf(%rsp), %eax
movzbl 0x25(%rsp), %ecx
cmpl %ecx, %eax
jge 0x32a11
movq 0x2967c(%rip), %rdi     # 0x5bf58
movzbl 0x27(%rsp), %esi
callq 0x228e0
movq 0x2966b(%rip), %rdi     # 0x5bf58
movzbl 0x26(%rsp), %esi
callq 0x22810
movq 0x2965a(%rip), %rdi     # 0x5bf58
callq 0x22090
movq 0x2964e(%rip), %rdi     # 0x5bf58
movzbl 0x27(%rsp), %esi
callq 0x228e0
movb 0x27(%rsp), %al
movb %al, 0xe(%rsp)
movzbl 0x25(%rsp), %eax
movzbl 0xf(%rsp), %ecx
subl %ecx, %eax
cmpl $0x20, %eax
jge 0x3293f
movzbl 0x25(%rsp), %eax
movzbl 0xf(%rsp), %ecx
subl %ecx, %eax
movl %eax, 0x8(%rsp)
jmp 0x3294a
movl $0x20, %eax
movl %eax, 0x8(%rsp)
jmp 0x3294a
movb 0xe(%rsp), %cl
movl 0x8(%rsp), %eax
movq 0x295ff(%rip), %rdi     # 0x5bf58
movzbl %cl, %esi
movzbl %al, %edx
callq 0x23060
movq 0x295ed(%rip), %rdi     # 0x5bf58
callq 0x22920
movl %eax, %ecx
xorl %eax, %eax
cmpl $0x0, %ecx
movb %al, 0x7(%rsp)
je 0x329ac
movzwl 0x16(%rsp), %ecx
movb $0x1, %al
cmpl $0x0, %ecx
movb %al, 0x6(%rsp)
je 0x329a4
callq 0x22b10
subl 0x10(%rsp), %eax
movzwl 0x16(%rsp), %ecx
cmpl %ecx, %eax
setb %al
movb %al, 0x6(%rsp)
movb 0x6(%rsp), %al
movb %al, 0x7(%rsp)
movb 0x7(%rsp), %al
testb $0x1, %al
jne 0x329b6
jmp 0x329de
movq 0x2959b(%rip), %rdi     # 0x5bf58
callq 0x23210
movb %al, %dl
movq 0x18(%rsp), %rax
movsbq 0x15(%rsp), %rcx
movb %dl, (%rax,%rcx)
movb 0x15(%rsp), %al
addb $0x1, %al
movb %al, 0x15(%rsp)
jmp 0x32964
jmp 0x329e0
movzbl 0x25(%rsp), %eax
cmpl $0x20, %eax
jge 0x329f4
movzbl 0x25(%rsp), %eax
movl %eax, (%rsp)
jmp 0x329fe
movl $0x20, %eax
movl %eax, (%rsp)
jmp 0x329fe
movl (%rsp), %ecx
movzbl 0xf(%rsp), %eax
addl %ecx, %eax
movb %al, 0xf(%rsp)
jmp 0x328c3
movzwl 0x16(%rsp), %eax
cmpl $0x0, %eax
jle 0x32a40
callq 0x22b10
subl 0x10(%rsp), %eax
movzwl 0x16(%rsp), %ecx
cmpl %ecx, %eax
jb 0x32a40
movsbl 0x15(%rsp), %eax
movzbl 0x25(%rsp), %ecx
cmpl %ecx, %eax
jge 0x32a40
movb $-0x1, 0x15(%rsp)
movb 0x15(%rsp), %al
addq $0x28, %rsp
retq
nopl (%rax)