0

I'm trying to read a code from a QR reader with python. Have used pigpio example from here http://abyz.me.uk/rpi/pigpio/examples.html#Python_wiegand_py

When I scan a QR it returns bits=34 value=12835750879 which is too long, the code should be 10 digit only. The QR sends 34 bits, and the guy that installed it said I need to ignore the last 2 bits, to take only 0-31, thing is I don't really understand the code, I come from PHP, which has nothing to do with bits and memory.

This is the part of the code that deals with the reading, I think somewhere in the _cb function.

Can somebody help me understand the code better so I can go into the right direction?

   def __init__(self, pi, gpio_0, gpio_1, callback, bit_timeout=5):

      """
      Instantiate with the pi, gpio for 0 (green wire), the gpio for 1
      (white wire), the callback function, and the bit timeout in
      milliseconds which indicates the end of a code.

      The callback is passed the code length in bits and the value.
      """

      self.pi = pi
      self.gpio_0 = gpio_0
      self.gpio_1 = gpio_1

      self.callback = callback

      self.bit_timeout = bit_timeout

      self.in_code = False

      self.pi.set_mode(gpio_0, pigpio.INPUT)
      self.pi.set_mode(gpio_1, pigpio.INPUT)

      self.pi.set_pull_up_down(gpio_0, pigpio.PUD_UP)
      self.pi.set_pull_up_down(gpio_1, pigpio.PUD_UP)

      self.cb_0 = self.pi.callback(gpio_0, pigpio.FALLING_EDGE, self._cb)
      self.cb_1 = self.pi.callback(gpio_1, pigpio.FALLING_EDGE, self._cb)

   def _cb(self, gpio, level, tick):

      """
      Accumulate bits until both gpios 0 and 1 timeout.
      """

      if level < pigpio.TIMEOUT:

         if self.in_code == False:
            self.bits = 1
            self.num = 0

            self.in_code = True
            self.code_timeout = 0
            self.pi.set_watchdog(self.gpio_0, self.bit_timeout)
            self.pi.set_watchdog(self.gpio_1, self.bit_timeout)
         else:
            self.bits += 1
            self.num = self.num << 1

         if gpio == self.gpio_0:
            self.code_timeout = self.code_timeout & 2 # clear gpio 0 timeout
         else:
            self.code_timeout = self.code_timeout & 1 # clear gpio 1 timeout
            self.num = self.num | 1

      else:

         if self.in_code:

            if gpio == self.gpio_0:
               self.code_timeout = self.code_timeout | 1 # timeout gpio 0
            else:
               self.code_timeout = self.code_timeout | 2 # timeout gpio 1

            if self.code_timeout == 3: # both gpios timed out
               self.pi.set_watchdog(self.gpio_0, 0)
               self.pi.set_watchdog(self.gpio_1, 0)
               self.in_code = False
               self.callback(self.bits, self.num)
alex
  • 51
  • 5
  • @Guimoute Indeed, and 2^34 it's over 1B, so that's why I get 11 digits. – alex Jan 20 '23 at 16:33
  • The problem with his code is that it's not very clear. Using `self.num = self.num << 1` and `self.num | 1` makes `self.num` a base-10 integer that gets updated and pushed around by new bits, but you cannot see the bits directly without converting to binary yourself, and it's less obvious than appending the bits to a list and converting the list to a number at the end. – Guimoute Jan 20 '23 at 16:35

1 Answers1

1

To remove the two last bits, you can convert the integer self.num to a binary string with bin(), trim off two characters, then convert back to integer.

Here is an example:

num = 2**34 - 1 # 17179869183
num_b = bin(num) # '0b1111111111111111111111111111111111'
num = int(num_b[:-2], base=2) # 4294967295

So you want to use int(bin(self.num)[:-2], 2) somewhere in your code where you retrieve the complete QR code.

Guimoute
  • 4,407
  • 3
  • 12
  • 28
  • Have tried your code to convert "12835750879" and it returned "3208937719", and the scanned QR was "2122908143". I tried a few minutes ago for an early return if `self.bits == 32` and it gave me 3208937718, which was somehow 1 less than your code. – alex Jan 20 '23 at 16:57
  • 2
    Have found the solution, I had to remove first and last char, not last two. I changed line 3 of your solution to `num = int('0b' + num_b[3:-1], base=2)` and it returns "2122908143" from "3208937719" – alex Jan 20 '23 at 17:22
  • Oh, so they meant ignoring the 2 leftmost bits instead of rightmost. Good good! – Guimoute Jan 20 '23 at 17:35