The application code of sparkFun, has the following line which is difficult to understand.

It's requested 6, because it's requesting 6 bytes for HMC5883L module.

Wire.requestFrom(address, 6);


int TwoWire::available(void)
  return rxBufferLength - rxBufferIndex;

So, the available function should return return rxBufferLength - rxBufferIndex; where rxBufferIndex is modified in read function:

int TwoWire::read(void)
  int value = -1;

  // get each successive byte on each call
  if(rxBufferIndex < rxBufferLength){
    value = rxBuffer[rxBufferIndex];

  return value;

But, my current question is why decrementing return rxBufferLength - rxBufferIndex; where rxBufferIndex is initialized to 0 all the time, and there's no chance the returned value would be less than 6, because that would terminate the if statement?

  • What is the rxBufferLength value in your example?
    – user31481
    Dec 16 '17 at 15:44
  • 6 according to HMC5883L 6 bytes data.
    – R1S8K
    Dec 21 '17 at 17:31

rxBufferLength is the number of bytes that have been received. rxBufferIndex is the byte you would next be handed with a read() function call.

So if you have received 6 bytes from the slave (which you will, since that is how many you requested) but not read any the available would be 6. Ergo, 6 <= 6. I.e., you asked for 6, it collected 6, and you are checking that it got at least 6 (it can never be >6 since you only asked for 6, so why they look for at least 6 I don't know).

rxBufferIndex is never decremented. It is incremented when you read a byte, up until rxBufferLength == rxBufferIndex at which point there is 0 bytes available.

But, my current question is why decrementing return rxBufferLength - rxBufferIndex; where rxBufferIndex is initialized to 0 all the time, and there's no chance the returned value would be less than 6, because that would terminate the if statement?

The way that Wire.h works is that available() will always return the number of bytes you requested if the call to requestFrom() succeeded until you first read some of that data. If you request 6 and the call worked then you have 6. The if could just as well be written as:

if (Wire.available()) {...

since it will always be 6 immediately after a successful call. However, that makes assumptions about how the Wire API works and could be subject to change in the future or operate differently on different platforms.

So it checks that, right after the call to requestFrom() for 6 bytes it actually got at least 6 bytes. Without seeing what is inside the conditional if, all I can do is make assumptions, but I would assume that it is then reading those 6 bytes, and so it wouldn't care if there happened to be more for some reason. But it doesn't want there to be 5 or fewer bytes available when it is reading 6 of them.

An if statement doesn't "terminate" if its condition becomes false once it has been executed. It's not like a while that keeps running until it's false - it's a single decision made at a single point in time. If anything changes in the future that would have caused a difference decision to be made (e.g., you read() a byte, so available() would now return 5), the decision that has been made still stands.

An analogy for you:

You want to go out for a good healthy walk - but only if it's not raining.

if (!raining) {

You go out for your walk to the shops, get a coffee, do some more shopping, and then walk home - but you only start doing that if it's not raining. If it starts raining while you're out you don't suddenly teleport back home. You could make the decision, when you come out of the cafe and see it's raining, to cut your shopping trip short, but you have to actively make that decision. Just because raining becomes true doesn't affect the fact that you are outside and walking.

  • I edited the question.
    – R1S8K
    Dec 16 '17 at 17:38
  • I think you're getting confused about what n if is.
    – Majenko
    Dec 16 '17 at 18:43
  • What confused me is if(6<=Wire.available()) because available returns rxBufferLength - rxBufferIndex; so if rxBufferLength is 6 and rxBufferIndex is 0, then available returns 6, which is true in this case. But, if rxBufferIndex is 1 or 2, then available returns 5 or 4, which is false. So, how's that if statement is working? Does if(6<=Wire.available()) returns the value one time, or it returns with all rxBufferIndex increments inside wire library?
    – R1S8K
    Dec 21 '17 at 17:37
  • 1
    @PerchEagle At the moment the if() executes Wire.available() will equal 6. That is the only time the if() executes, and it can only ever give 6, since nothing has been read at that point.
    – Majenko
    Dec 21 '17 at 18:33
  • OK, I understand now, it runs only one time and the function every time returns 6. Thank you :) but I have another problem, the good news I succeeded accomplishing my I2C code, and that was amazing, but I have a new problem passing an array to I2C_tx function, I don't know why it's not working. I should ask about it in a new post.
    – R1S8K
    Dec 23 '17 at 6:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.