bitwise tilde operator

if this were a boolean or a 1 or 0 i would understand 1 = 0 or 0=1 but when were talking about a hex value i dont understand what the value would be. if i understand right ~ would flip the binary bits of that value? but when i use the bitwise NOT operator like this what does the value equal? i think it == 00001
but i cant figure out the persons logic with this method. Can someone please explain this to me

enum TiStates {
tiEnabled = 0x80,
tiRunning = 0x40,
tiOnValue = 0x20,
tiUpdated = 0x10,
tiSetable = tiEnabled + tiRunning + tiOnValue,
};

Timers*.status &= ~tiUpdated;*
```
*#pragma once

struct Hdr {
  byte type;
  byte to;
  byte from;
  byte id;
  Hdr() : type(0), to(0), from(0), id(0) {}
  Hdr(byte inType, byte inTo, byte inFrom) : type(inType), to(inTo), from(inFrom), id('a') {}
  void incId() {
    if (id++ == 'z') {
      id = 'a';
    }
  }
  bool isType(byte inType) {
    return type == inType;
  }
  bool isTypeTo(byte inType, byte inTo) {
    return isType(inType) && to == inTo;
  }
};

enum TiStates {
  tiEnabled = 0x80,
  tiRunning = 0x40,
  tiOnValue = 0x20,
  tiUpdated = 0x10,
  tiSetable = tiEnabled + tiRunning + tiOnValue,
};

struct aTimer {
  byte status;
  uint16_t onTime;
  uint16_t offTime;
  aTimer(uint16_t iOn, uint16_t iOff) : status(0), onTime(iOn), offTime(iOff) {}
  aTimer() : status(0), onTime(0), offTime(0) {}
};

struct TimerInfos : public Hdr {
    aTimer Timers[4];
    int timer;
    int relay1Mode = 1;
    int relay2Mode = 1;
    int relay3Mode = 1;
    int relay4Mode = 1;
    byte timer1Enabled;
    byte timer2Enabled;
    byte timer3Enabled;
    byte timer4Enabled;
    int timer1State = 0;
    int timer2State = 0;
    int timer3State = 0;
    int timer4State = 0;
    bool timer1On = false;
    bool timer2On = false;
    bool timer3On = false;
    bool timer4On = false;
    int timerRunStatus;
    TimerInfos (byte from) : Hdr('T', '*', from), timer(1), timerRunStatus(0), timer1Enabled(1), timer2Enabled(1), timer3Enabled(1), timer4Enabled(1), Timers{  aTimer(111, 111), aTimer(111, 111), aTimer(111, 111), aTimer(111, 111)  } {}

bool setFlags(byte timerNumber, byte flags) {
      byte previous = Timers[timerNumber].status;
      Timers[timerNumber].status |= flags & tiSetable;
      return changedFlags(timerNumber, previous);
    }
    bool clrFlags(byte timerNumber, byte flags) {
      byte previous = Timers[timerNumber].status;
      Timers[timerNumber].status &= ~(flags & tiSetable);
      return changedFlags(timerNumber, previous);
    }
    bool copyFlags(byte timerNumber, byte flags) {
      byte previous = Timers[timerNumber].status & tiSetable;
      flags &= tiSetable;
      if (previous != flags) {
        Timers[timerNumber].status = flags | tiUpdated;
        return true;
      }
      return false;
    }
    bool setOnTime(byte timerNumber, uint16_t value) {
      uint16_t previous = Timers[timerNumber].onTime;
      Timers[timerNumber].onTime = value;

return changedOn(timerNumber, previous);
    }
    bool setOffTime(byte timerNumber, uint16_t value) {
      uint16_t previous = Timers[timerNumber].offTime;
      Timers[timerNumber].offTime = value;
      return changedOff(timerNumber, previous);
    }
    bool anyUpdated() {
      bool upd = false;
      for (byte i = 0; i < sizeof(Timers) / sizeof(Timers[0]); i++) {
        upd |= Timers[i].status & tiUpdated;
      }
      return upd;
    }
    void clrUpdated() {
      for (byte i = 0; i < sizeof(Timers) / sizeof(Timers[0]); i++) {
        Timers[i].status &= ~tiUpdated;
      }
    }
    bool setFrom(TimerInfos* in) {
      bool changes = false;
      clrUpdated();
      for (byte i = 0; i < sizeof(Timers) / sizeof(Timers[0]); i++) {
        changes |= copyFlags(i, in->Timers[i].status);
        changes |= setOnTime(i, in->Timers[i].onTime);
        changes |= setOffTime(i, in->Timers[i].offTime);
      }
      return changes;
    }
  protected:
    bool changedFlags(byte timerNumber, byte previous) {
      return adjustChangedFlag(timerNumber, (Timers[timerNumber].status ^ previous) & tiSetable);
    }
    bool changedOn(byte timerNumber, uint16_t previous) {
      return adjustChangedFlag(timerNumber, Timers[timerNumber].onTime != previous);
    }
    bool changedOff(byte timerNumber, uint16_t previous) {
      return adjustChangedFlag(timerNumber, Timers[timerNumber].offTime != previous);
    }
    bool adjustChangedFlag(byte timerNumber, bool different) {
      if (different) {
        Timers[timerNumber].status |= tiUpdated;
        //} else {
        //  Timers[timerNumber].status &= ~tiUpdated;
      }
      return different;
    }
};

struct Command : public Hdr {
  byte text[32 - sizeof(Hdr)];
  Command(byte from) : Hdr('!', '?', from), text("") {}
  byte setData(byte target, const char* txt) {
    to = target;
    strcpy((char*)text, txt);
    return strlen(txt) + 1 + sizeof(Hdr);
  }

};*
```

  Timers.status &= ~tiUpdated;

That's the standard construct for clearing a bit. It isn't needed in the snippet you posted because that bit isn't set but I assume it might be elsewhere in the program.

Let's say status had 00001101 and tiUpdated is 0x01 or 00000001

So let's bitwise not the mask

~00000001 == 11111110

And if we AND that with the original byte

00001101
&11111110

Clearly equals

00001100

Okay that sort of cleared that up. since this is the first time iv'e ever really used bitwise operators its all confusing right now. That code i posted is a header file for all the timer parameters and TimersInfo structure.

in the program the person has created a way to set some flags when parameters are changed. I would like to understand. the way i see it "Timers[timerNumber].status" gets updated with the values of memebers from TiStates but we start doing a bunch of binary / bitwise operators and i get lost in binary real fast.

Here is in the main program inside the only function that handles the functions inside the header file that change Timers[].status

bool handleTCommand(const char* buffer) {
  buffer = skipBlanks(buffer);
  if (*buffer < '0' || *buffer > '3') {
    return false;
  }
  byte tIndex = *buffer - '0';
  buffer = skipBlanks(buffer + 1);
  switch (*buffer) {
    case '0'...'9': {
        char* behind;
        uint32_t value = strtoul(buffer, &behind, 0);
        if (value & 0xFFFF0000) {
          return false;
        }
        tInfos.setOnTime(tIndex, value);
        behind = (char*)skipBlanks(behind);
        if (*behind == ',') {
          value = strtoul(behind + 1, &behind, 0);
          if (value & 0xFFFF0000) {
            return false;
          }
          tInfos.setOffTime(tIndex, value);
        }
      }
      break;
    case 'e':
      tInfos.setFlags(tIndex, tiEnabled);
      if (tIndex == 0) {
        tInfos.timer1Enabled = true;
      }
      if (tIndex == 1) {
        tInfos.timer2Enabled = true;
      }

      if (tIndex == 2) {
        tInfos.timer3Enabled = true;
      }

      if (tIndex == 3) {
        tInfos.timer4Enabled = true;
      }
      break;
    case 'd':
      tInfos.clrFlags(tIndex, tiEnabled);
      if (tIndex == 0) {
        tInfos.timer1Enabled = false;
      }
      if (tIndex == 1) {
        tInfos.timer2Enabled = false;
      }

      if (tIndex == 2) {
        tInfos.timer3Enabled = false;
      }

      if (tIndex == 3) {
        tInfos.timer4Enabled = false;
      }


      tInfos.clrFlags(tIndex, tiEnabled);

      break;
    case 'g':
      tInfos.setFlags(tIndex, tiRunning);
 
      break;
    case 's':
      tInfos.clrFlags(tIndex, tiRunning);
      break;
    default:
      return false;
  }
  return true;
}

const char* skipBlanks(const char* buffer) {
  while (*buffer == ' ') {
    buffer++;
  }
  return buffer;
}

If you are willing to explain this further and im missing a piece of the program crucial to understanding let me know. I just want to understand what happening here. keep in mind obviously i am a beginner,

if (value & 0xFFFF0000) {
          return false;
        }

Are you talking about that line? Let's reduce it so we're not dealing with such big numbers.

Let's say it was:

if (value & 0xF0) {
          return false;
        }

So it's just one byte. Now play around with some different byte values and AND them with 0xF0 (11110000) and you'll see that anything with bits set in the high four bits will give you something with a bit set in that position (if statement will be true since non-zero) and if you AND in anything with no bits set in the top four bits then it doesn't matter what is in the bottom four bits because AND with 0 is always 0.

So what that line really says is " if any bits are set in the high 16 bits of this 32 bit value..."

Delta_G:

if (value & 0xFFFF0000) {

return false;
        }




Are you talking about that line? Let's reduce it so we're not dealing with such big numbers.

Let's say it was:



if (value & 0xF0) {
          return false;
        }




So it's just one byte. Now play around with some different byte values and AND them with 0xF0 (11110000) and you'll see that anything with bits set in the high four bits will give you something with a bit set in that position (if statement will be true since non-zero) and if you AND in anything with no bits set in the top four bits then it doesn't matter what is in the bottom four bits because AND with 0 is always 0. 

So what that line really says is " if any bits are set in the high 16 bits of this 32 bit value..."

I tried to make my own example similar to what you showed me and im starting to understand it.

My example code,

byte value = 1111;
byte valueHEX=0xFFFF0000;

enum TiStates {
  tiEnabled = 0x80,
  tiRunning = 0x40,
  tiOnValue = 0x20,
  tiUpdated = 0x10,
  tiSetable = tiEnabled + tiRunning + tiOnValue,
};

void setup() {
Serial.begin(9600);
  Serial.print("hello");
}

void loop() {
 if (value & '0xFFFF0000'){
  Serial.println("PASS");
 }
}

You mentioned something about the first 4 bits. I'm looking at the wiki on Bitwise operation but it don't specify anything i don't think about the first 4 bits. I think i understand about the most significant bits but i don't think it mentioned anything about the first 4 significant bits. Can you explain why

value = 1111; // is true
value =1111111111111111;// returns false and dose not Serial.print //too large of a number?

You mentioned something about the first 4 bits. I'm looking at the wiki on Bitwise operation but it don't specify anything i don't think about the first 4 bits. I think i understand about the most significant bits but i don't think it mentioned anything about the first 4 significant bits. Can you explain w

No, the bitwise AND works on all the bits. But the mask only had bits set in the top four so when you AND it with some other value then only bits in the top four places will make it through.

11000101 has bits in the top four places
& 11110000 masks for the top four places

= 11000000 ends up true.

00001101 has no bits in the top four places
& 11110000 masks for the top four places

= 00000000 evaluates to 0 so it's false.

The top four bits comes from the mask that you're ANDing with.

If you used 0x0F instead of 0xF0 then it would be masking for the bottom 4 bits.

If you used 0x08 instead then it would mask for the bottom 3 bits.

byte value = 1111;
byte valueHEX=0xFFFF0000;

1111 in binary is 0b0000010001010111

1111111111111111 in binary is 0b11111100101000110010110111000101010111000111000111

Does your result make a little more sense now?

If you want to assign binary values then you need 0b.

val = 0b1111

okay in my example why doesn't the 3rd if statement print pass. what i think im doing is moving the 2 second bit in MASK to the left by 1 why does this not equal what i think it does?

byte value = 1111;
byte value2 = 1;
byte MASKhigh='0xBITS0000';
byte MASKlow='0x00001111';
byte MASK='0x0F000000';



void setup() {
Serial.begin(9600);
  Serial.print("hello");
}
void loop() {
 if (value & MASKhigh){
 // Serial.println("First 4 BITS in MASKhigh are set");
 }
  if (value & MASKlow){
 // Serial.println("Last 4 BITS in MASKlow are set");
 }
  if (value2 & MASK << 1){
  Serial.println("PASS");
 }

}
if (value2 & MASK << 1){

value2 is 1. Your mask is 1111000000000000000000000000

When you AND that with 1:

11110000000000000000
&000000000000000001


000000000000000000

(I didn't count the zeroes. But you get the point.)

And that's false.

Delta_G:

if (value2 & MASK << 1){

value2 is 1. Your mask is 1111000000000000000000000000

When you AND that with 1:

11110000000000000000
&000000000000000001


000000000000000000

(I didn't count the zeroes. But you get the point.)

And that's false.

Im still a little confused. Why does value 2 = 000000001? i figured the 1 would be on the left side of the scale. would this mean value2=11 would be 000000011?

i pictured

11110000000000000000
&100000000000000000

000000000000000000

but then i add the left bitshift in the 3rd if statement so i though it would really look like this,

111000000000000000
&100000000000000000

100000000000000000

What am i missing here?

if value2 = 110 // it prints pass
if value2 = 111 // it prints pass

val = 1. That's one. Uno. converting 1 to binary is really easy. It's still just 1. And that 1 is in the 1's place.

If it was going to put the 1 in the first place then that would be:

val = 128;

if we're talking about 8 bits or (unsigned)

val = 32768; for 16 bits (unsigned)

would this mean value2=11 would be 000000011?

Absolutely not

value2 = 11;

11 in binary is 00001011

If you want to assign a binary value AND I'VE SAID THIS TWICE NOW use 0b.

val = 0b11; That gives you 00000011

STOP assigning decimal values and trying to pretend that they're binary. That's just going to confuse you more.

Delta_G:

would this mean value2=11 would be 000000011?

Absolutely not

value2 = 11;

11 in binary is 00001011

If you want to assign a binary value AND I'VE SAID THIS TWICE NOW use 0b.

val = 0b11; That gives you 00000011

STOP assigning decimal values and trying to pretend that they're binary. That's just going to confuse you more.

That's what i was missing thankyou

I'm still missing something, will the if statement be true if only 1 bit matches or all the bits in the byte? im trying to leftshift this mask but i'm get getting the results i expected.

byte value2 = '0b111';
byte MASK = '0b111';

void setup() {
  Serial.begin(9600);
}
void loop() {

  if (value2 & (MASK <<1)) {
    Serial.println("PASS");
  }
}

this is what i visualize when bitshifting "byte MASK" bits left,

00000111 //MASK not bitshifted
00001110 //MASK bit shifted left by 1

Heres another example i thought should work,

byte value2 = '0b00011100';
byte MASK = '0b00000111';

void setup() {
  Serial.begin(9600);
  Serial.print("hello");
}
void loop() {

  if (value2 & (MASK <<2)) {
    Serial.println("PASS");
  }
}

It was how i was initializing the variable for binary it appears the correct way to define the variable is with B

byte value2 = B00011110;
byte MASK = B00000111;

I think.

The B prefix is a very limited Arduino-specific facility.
The 0b prefix is much more common and allows larger constants to be defined

Better still, use hex.

AWOL:
The B prefix is a very limited Arduino-specific facility.
The 0b prefix is much more common and allows larger constants to be defined

Better still, use hex.

im getting ready to step into hex. but why didnt it work when i used,

byte value2 = '0b00011100';
byte MASK = '0b00000111';

EDIT: Correct way,
byte value2 = 0b00000111;
byte MASK = 0b00000111;

Single quotes denote a character constant.

notsolowki:
I'm still missing something, will the if statement be true if only 1 bit matches or all the bits in the byte? im trying to leftshift this mask but i'm get getting the results i expected.

byte value2 = '0b111';

byte MASK = '0b111';

void setup() {
  Serial.begin(9600);
}
void loop() {

if (value2 & (MASK <<1)) {
    Serial.println("PASS");
  }
}





this is what i visualize when bitshifting "byte MASK" bits left,

00000111 //MASK not bitshifted
00001110 //MASK bit shifted left by 1

Heres another example i thought should work,



byte value2 = '0b00011100';
byte MASK = '0b00000111';

void setup() {
  Serial.begin(9600);
  Serial.print("hello");
}
void loop() {

if (value2 & (MASK <<2)) {
    Serial.println("PASS");
  }
}

Why the hell did you put quotes around the numbers?