From 67ec10049abf66ff7ebbc94cd2a05611e6a4faba Mon Sep 17 00:00:00 2001 From: dahanzimin <353767514@qq.com> Date: Tue, 21 Oct 2025 20:15:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0OLED+TFT=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E5=99=A8=E6=94=AF=E6=8C=81=E4=BA=8C=E7=BB=B4=E7=A0=81=E7=94=9F?= =?UTF-8?q?=E6=88=90=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../origin/build/lib/adafruit_miniqr.py | 602 ++++++++++++++++++ .../micropython/origin/build/lib/uframebuf.py | 18 + 2 files changed, 620 insertions(+) create mode 100644 boards/default_src/micropython/origin/build/lib/adafruit_miniqr.py diff --git a/boards/default_src/micropython/origin/build/lib/adafruit_miniqr.py b/boards/default_src/micropython/origin/build/lib/adafruit_miniqr.py new file mode 100644 index 00000000..f8fcb04c --- /dev/null +++ b/boards/default_src/micropython/origin/build/lib/adafruit_miniqr.py @@ -0,0 +1,602 @@ +# SPDX-FileCopyrightText: 2009 Kazuhiko Arase +# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# Ported from the Javascript library by Sam Curren +# QRCode for Javascript +# http://d-project.googlecode.com/svn/trunk/misc/qrcode/js/qrcode.js +# +# Minimized for CircuitPython by ladyada for adafruit industries +# +# The word "QR Code" is registered trademark of +# DENSO WAVE INCORPORATED +# http://www.denso-wave.com/qrcode/faqpatent-e.html +""" +`adafruit_miniqr` +==================================================== + +A non-hardware dependant miniature QR generator library. All native Python! + +* Author(s): ladyada + +Implementation Notes +-------------------- + +**Hardware:** + +* Any! + +**Software and Dependencies:** + +* Python 3 + +""" + +# imports +import math + +try: + from typing import Dict, List, Optional, Tuple +except ImportError: + pass + +__version__ = "0.0.0+auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_miniQR.git" + +# Consts! +M = 0 +L = 1 +H = 2 +Q = 3 + +_MODE_8BIT_BYTE = 1 << 2 +_PAD0 = 0xEC +_PAD1 = 0x11 + +# Optimized polynomial helpers + + +def _glog(n: int) -> int: + """Lookup log(n) from pre-calculated byte table""" + if n < 1: + raise ValueError("glog(" + n + ")") + return LOG_TABLE[n] + + +def _gexp(n: int) -> int: + """Lookup exp(n) from pre-calculated byte table""" + while n < 0: + n += 255 + while n >= 256: + n -= 255 + return EXP_TABLE[n] + + +EXP_TABLE = b"\x01\x02\x04\x08\x10 @\x80\x1d:t\xe8\xcd\x87\x13&L\x98-Z\xb4u\xea\xc9\x8f\x03\x06\x0c\x180`\xc0\x9d'N\x9c%J\x945j\xd4\xb5w\xee\xc1\x9f#F\x8c\x05\n\x14(P\xa0]\xbai\xd2\xb9o\xde\xa1_\xbea\xc2\x99/^\xbce\xca\x89\x0f\x1e|\xf8\xed\xc7\x93;v\xec\xc5\x973f\xcc\x85\x17.\\\xb8m\xda\xa9O\x9e!B\x84\x15*T\xa8M\x9a)R\xa4U\xaaI\x929r\xe4\xd5\xb7s\xe6\xd1\xbfc\xc6\x91?~\xfc\xe5\xd7\xb3{\xf6\xf1\xff\xe3\xdb\xabK\x961b\xc4\x957n\xdc\xa5W\xaeA\x82\x192d\xc8\x8d\x07\x0e\x1c8p\xe0\xdd\xa7S\xa6Q\xa2Y\xb2y\xf2\xf9\xef\xc3\x9b+V\xacE\x8a\t\x12$H\x90=z\xf4\xf5\xf7\xf3\xfb\xeb\xcb\x8b\x0b\x16,X\xb0}\xfa\xe9\xcf\x83\x1b6l\xd8\xadG\x8e\x01" # noqa: E501 + +LOG_TABLE = b"\x00\x00\x01\x19\x022\x1a\xc6\x03\xdf3\xee\x1bh\xc7K\x04d\xe0\x0e4\x8d\xef\x81\x1c\xc1i\xf8\xc8\x08Lq\x05\x8ae/\xe1$\x0f!5\x93\x8e\xda\xf0\x12\x82E\x1d\xb5\xc2}j'\xf9\xb9\xc9\x9a\txM\xe4r\xa6\x06\xbf\x8bbf\xdd0\xfd\xe2\x98%\xb3\x10\x91\"\x886\xd0\x94\xce\x8f\x96\xdb\xbd\xf1\xd2\x13\\\x838F@\x1eB\xb6\xa3\xc3H~nk:(T\xfa\x85\xba=\xca^\x9b\x9f\n\x15y+N\xd4\xe5\xacs\xf3\xa7W\x07p\xc0\xf7\x8c\x80c\rgJ\xde\xed1\xc5\xfe\x18\xe3\xa5\x99w&\xb8\xb4|\x11D\x92\xd9# \x89.7?\xd1[\x95\xbc\xcf\xcd\x90\x87\x97\xb2\xdc\xfc\xbea\xf2V\xd3\xab\x14*]\x9e\x84<9SGmA\xa2\x1f-C\xd8\xb7{\xa4v\xc4\x17I\xec\x7f\x0co\xf6l\xa1;R)\x9dU\xaa\xfb`\x86\xb1\xbb\xcc>Z\xcbY_\xb0\x9c\xa9\xa0Q\x0b\xf5\x16\xebzu,\xd7O\xae\xd5\xe9\xe6\xe7\xad\xe8t\xd6\xf4\xea\xa8PX\xaf" # noqa: E501 + + +class QRCode: + """The generator class for QR code matrices""" + + def __init__(self, *, qr_type: Optional[int] = None, error_correct: int = L): + """Initialize an empty QR code. You can define the `qr_type` (size) + of the code matrix, or have the libary auto-select the smallest + match. Default `error_correct` is type L (7%), but you can select M, + Q or H.""" + self.type = qr_type + self.ECC = error_correct + self.matrix = None + self.module_count = 0 + self.data_cache = None + self.data_list = [] + + def add_data(self, data: bytes) -> None: + """Add more data to the QR code, must be bytestring stype""" + self.data_list.append(data) + datalen = sum(len(x) for x in self.data_list) + if not self.type: + for qr_type in range(1, 10): + rs_blocks = _get_rs_blocks(qr_type, self.ECC) + total_data_count = 0 + for block in rs_blocks: + total_data_count += block["data"] + if total_data_count > datalen: + self.type = qr_type + break + self.data_cache = None + + def make(self, *, test: bool = False, mask_pattern: int = 0) -> None: + """Perform the actual generation of the QR matrix. To keep things + small and speedy we don't generate all 8 mask patterns and pick + the best. Instead, please pass in a desired mask_pattern, the + default mask is 0.""" + self.module_count = self.type * 4 + 17 + self.matrix = QRBitMatrix(self.module_count, self.module_count) + + self._setup_position_probe_pattern(0, 0) + self._setup_position_probe_pattern(self.module_count - 7, 0) + self._setup_position_probe_pattern(0, self.module_count - 7) + self._setup_position_adjust_pattern() + self._setup_timing_pattern() + self._setup_type_info(test, mask_pattern) + + if self.type >= 7: + self._setup_type_number(test) + + if self.data_cache is None: + self.data_cache = QRCode._create_data(self.type, self.ECC, self.data_list) + self._map_data(self.data_cache, mask_pattern) + + def _setup_position_probe_pattern(self, row: int, col: int) -> None: + """Add the positition probe data pixels to the matrix""" + for r in range(-1, 8): + if row + r <= -1 or self.module_count <= row + r: + continue + for c in range(-1, 8): + if col + c <= -1 or self.module_count <= col + c: + continue + test = ( + (0 <= r <= 6 and (c in (0, 6))) + or (0 <= c <= 6 and (r in (0, 6))) + or (2 <= r <= 4 and 2 <= c <= 4) + ) + self.matrix[row + r, col + c] = test + + def _setup_timing_pattern(self) -> None: + """Add the timing data pixels to the matrix""" + for r in range(8, self.module_count - 8): + if self.matrix[r, 6] is not None: + continue + self.matrix[r, 6] = r % 2 == 0 + + for c in range(8, self.module_count - 8): + if self.matrix[6, c] is not None: + continue + self.matrix[6, c] = c % 2 == 0 + + def _setup_position_adjust_pattern(self) -> None: + """Add the position adjust data pixels to the matrix""" + pos = QRUtil.get_pattern_position(self.type) + + for row in pos: + for col in pos: + if self.matrix[row, col] is not None: + continue + + for r in range(-2, 3): + for c in range(-2, 3): + test = abs(r) == 2 or abs(c) == 2 or (r == 0 and c == 0) + self.matrix[row + r, col + c] = test + + def _setup_type_number(self, test: bool) -> None: + """Add the type number pixels to the matrix""" + bits = QRUtil.get_BCH_type_number(self.type) + + for i in range(18): + mod = not test and ((bits >> i) & 1) == 1 + self.matrix[i // 3, i % 3 + self.module_count - 8 - 3] = mod + + for i in range(18): + mod = not test and ((bits >> i) & 1) == 1 + self.matrix[i % 3 + self.module_count - 8 - 3, i // 3] = mod + + def _setup_type_info(self, test: bool, mask_pattern: int) -> None: + """Add the type info pixels to the matrix""" + data = (self.ECC << 3) | mask_pattern + bits = QRUtil.get_BCH_type_info(data) + + # // vertical + for i in range(15): + mod = not test and ((bits >> i) & 1) == 1 + if i < 6: + self.matrix[i, 8] = mod + elif i < 8: + self.matrix[i + 1, 8] = mod + else: + self.matrix[self.module_count - 15 + i, 8] = mod + + # // horizontal + for i in range(15): + mod = not test and ((bits >> i) & 1) == 1 + if i < 8: + self.matrix[8, self.module_count - i - 1] = mod + elif i < 9: + self.matrix[8, 15 - i - 1 + 1] = mod + else: + self.matrix[8, 15 - i - 1] = mod + + # // fixed module + self.matrix[self.module_count - 8, 8] = not test + + def _map_data(self, data: bytes, mask_pattern: int) -> None: + """Map the data onto the QR code""" + inc = -1 + row = self.module_count - 1 + bit_idx = 7 + byte_idx = 0 + + for col in range(self.module_count - 1, 0, -2): + if col == 6: + col -= 1 # noqa: PLW2901 loop variable overwritten + + while True: + for c in range(2): + if self.matrix[row, col - c] is None: + dark = False + if byte_idx < len(data): + dark = ((data[byte_idx] >> bit_idx) & 1) == 1 + mask = QRUtil.get_mask(mask_pattern, row, col - c) + if mask: + dark = not dark + self.matrix[row, col - c] = dark + bit_idx -= 1 + if bit_idx == -1: + byte_idx += 1 + bit_idx = 7 + row += inc + if row < 0 or self.module_count <= row: + row -= inc + inc = -inc + break + + @staticmethod + def _create_data(qr_type: int, ecc: int, data_list: list) -> bytes: + """Check and format data into bit buffer""" + rs_blocks = _get_rs_blocks(qr_type, ecc) + + buffer = QRBitBuffer() + + for data in data_list: + if isinstance(data, str): + data = str.encode(data) # noqa: PLW2901 loop variable overwritten + buffer.put(_MODE_8BIT_BYTE, 4) + buffer.put(len(data), 8) + for byte in data: + buffer.put(byte, 8) + + # // calc num max data. + total_data_count = 0 + for block in rs_blocks: + total_data_count += block["data"] + + if buffer.get_length_bits() > total_data_count * 8: + raise RuntimeError( + "Code length overflow: %d > %d" % (buffer.get_length_bits(), total_data_count * 8) + ) + + # // end code + if buffer.get_length_bits() + 4 <= total_data_count * 8: + buffer.put(0, 4) + + # // padding + while buffer.get_length_bits() % 8 != 0: + buffer.put_bit(False) + + # // padding + while True: + if buffer.get_length_bits() >= total_data_count * 8: + break + buffer.put(_PAD0, 8) + if buffer.get_length_bits() >= total_data_count * 8: + break + buffer.put(_PAD1, 8) + + return QRCode._create_bytes(buffer, rs_blocks) + + @staticmethod + def _create_bytes(buffer: bytes, rs_blocks: List[Dict]) -> bytes: # noqa: PLR0912 Too many branches + """Perform error calculation math on bit buffer""" + + offset = 0 + max_dc_count = 0 + max_ec_count = 0 + + dcdata = [0] * len(rs_blocks) + ecdata = [0] * len(rs_blocks) + + for r, block in enumerate(rs_blocks): + dc_count = block["data"] + ec_count = block["total"] - dc_count + + max_dc_count = max(max_dc_count, dc_count) + max_ec_count = max(max_ec_count, ec_count) + + dcdata[r] = [0] * dc_count + + for i in range(len(dcdata[r])): + dcdata[r][i] = 0xFF & buffer.buffer[i + offset] + offset += dc_count + + rs_poly = QRUtil.get_error_correct_polynomial(ec_count) + mod_poly = QRPolynomial(dcdata[r], rs_poly.get_length() - 1) + + while True: + if mod_poly.get_length() - rs_poly.get_length() < 0: + break + ratio = _glog(mod_poly.get(0)) - _glog(rs_poly.get(0)) + num = [0 for x in range(mod_poly.get_length())] + for i in range(mod_poly.get_length()): + num[i] = mod_poly.get(i) + for i in range(rs_poly.get_length()): + num[i] ^= _gexp(_glog(rs_poly.get(i)) + ratio) + mod_poly = QRPolynomial(num, 0) + + ecdata[r] = [0 for x in range(rs_poly.get_length() - 1)] + for i in range(len(ecdata[r])): + mod_index = i + mod_poly.get_length() - len(ecdata[r]) + if mod_index >= 0: + ecdata[r][i] = mod_poly.get(mod_index) + else: + ecdata[r][i] = 0 + + total_code_count = 0 + for block in rs_blocks: + total_code_count += block["total"] + + data = [None] * total_code_count + index = 0 + + for i in range(max_dc_count): + for r in range(len(rs_blocks)): + if i < len(dcdata[r]): + data[index] = dcdata[r][i] + index += 1 + + for i in range(max_ec_count): + for r in range(len(rs_blocks)): + if i < len(ecdata[r]): + data[index] = ecdata[r][i] + index += 1 + + return data + + +class QRUtil: + """A selection of bit manipulation tools for QR generation and BCH encoding""" + + PATTERN_POSITION_TABLE = [ + b"", + b"\x06\x12", + b"\x06\x16", + b"\x06\x1a", + b"\x06\x1e", + b'\x06"', + b"\x06\x16&", + b"\x06\x18*", + b"\x06\x1a.", + b"\x06\x1c2", + ] + + G15 = 0b10100110111 + G18 = 0b1111100100101 + G15_MASK = 0b101010000010010 + + @staticmethod + def get_BCH_type_info(data: int) -> int: + """Encode with G15 BCH mask""" + d = data << 10 + while QRUtil.get_BCH_digit(d) - QRUtil.get_BCH_digit(QRUtil.G15) >= 0: + d ^= QRUtil.G15 << (QRUtil.get_BCH_digit(d) - QRUtil.get_BCH_digit(QRUtil.G15)) + + return ((data << 10) | d) ^ QRUtil.G15_MASK + + @staticmethod + def get_BCH_type_number(data: int) -> int: + """Encode with G18 BCH mask""" + d = data << 12 + while QRUtil.get_BCH_digit(d) - QRUtil.get_BCH_digit(QRUtil.G18) >= 0: + d ^= QRUtil.G18 << (QRUtil.get_BCH_digit(d) - QRUtil.get_BCH_digit(QRUtil.G18)) + return (data << 12) | d + + @staticmethod + def get_BCH_digit(data: int) -> int: + """Count digits in data""" + digit = 0 + while data != 0: + digit += 1 + data >>= 1 + return digit + + @staticmethod + def get_pattern_position(qr_type: int) -> bytes: + """The mask pattern position array for this QR type""" + return QRUtil.PATTERN_POSITION_TABLE[qr_type - 1] + + @staticmethod + def get_mask(mask: int, i: int, j: int) -> int: # noqa: PLR0911 Too many return statements + """Perform matching calculation on two vals for given pattern mask""" + if mask == 0: + return (i + j) % 2 == 0 + if mask == 1: + return i % 2 == 0 + if mask == 2: + return j % 3 == 0 + if mask == 3: + return (i + j) % 3 == 0 + if mask == 4: + return (math.floor(i / 2) + math.floor(j / 3)) % 2 == 0 + if mask == 5: + return (i * j) % 2 + (i * j) % 3 == 0 + if mask == 6: + return ((i * j) % 2 + (i * j) % 3) % 2 == 0 + if mask == 7: + return ((i * j) % 3 + (i + j) % 2) % 2 == 0 + raise ValueError("Bad mask pattern:" + mask) + + @staticmethod + def get_error_correct_polynomial(ecc_length: int) -> "QRPolynomial": + """Generate a ecc polynomial""" + poly = QRPolynomial([1], 0) + for i in range(ecc_length): + poly = poly.multiply(QRPolynomial([1, _gexp(i)], 0)) + return poly + + +class QRPolynomial: + """Structure for creating and manipulating error code polynomials""" + + def __init__(self, num: int, shift: int): + """Create a QR polynomial""" + if not num: + raise ValueError(num.length + "/" + shift) + offset = 0 + while offset < len(num) and num[offset] == 0: + offset += 1 + self.num = [0 for x in range(len(num) - offset + shift)] + for i in range(len(num) - offset): + self.num[i] = num[i + offset] + + def get(self, index: int) -> int: + """The exponent at the index location""" + return self.num[index] + + def get_length(self) -> int: + """Length of the poly""" + return len(self.num) + + def multiply(self, other_polynomial: "QRPolynomial") -> "QRPolynomial": + """Multiply two polynomials, returns a new one""" + num = [0 for x in range(self.get_length() + other_polynomial.get_length() - 1)] + + for i in range(self.get_length()): + for j in range(other_polynomial.get_length()): + num[i + j] ^= _gexp(_glog(self.get(i)) + _glog(other_polynomial.get(j))) + + return QRPolynomial(num, 0) + + +_QRRS_BLOCK_TABLE = ( + b"\x01\x1a\x10", + b"\x01\x1a\x13", + b"\x01\x1a\t", + b"\x01\x1a\r", + b"\x01,\x1c", + b'\x01,"', + b"\x01,\x10", + b"\x01,\x16", + b"\x01F,", + b"\x01F7", + b"\x02#\r", + b"\x02#\x11", + b"\x022 ", + b"\x01dP", + b"\x04\x19\t", + b"\x022\x18", + b"\x02C+", + b"\x01\x86l", + b'\x02!\x0b\x02"\x0c', + b'\x02!\x0f\x02"\x10', + b"\x04+\x1b", + b"\x02VD", + b"\x04+\x0f", + b"\x04+\x13", + b"\x041\x1f", + b"\x02bN", + b"\x04'\r\x01(\x0e", + b"\x02 \x0e\x04!\x0f", + b"\x02<&\x02='", + b"\x02ya", + b"\x04(\x0e\x02)\x0f", + b"\x04(\x12\x02)\x13", + b"\x03:$\x02;%", + b"\x02\x92t", + b"\x04$\x0c\x04%\r", + b"\x04$\x10\x04%\x11", +) + + +def _get_rs_blocks(qr_type: int, ecc: int) -> List[Dict]: + rs_block = _QRRS_BLOCK_TABLE[(qr_type - 1) * 4 + ecc] + + length = len(rs_block) // 3 + blocks = [] + for i in range(length): + count = rs_block[i * 3 + 0] + total = rs_block[i * 3 + 1] + data = rs_block[i * 3 + 2] + block = {"total": total, "data": data} + for _ in range(count): + blocks.append(block) + return blocks + + +class QRBitMatrix: + """A bit-packed storage class for matrices""" + + def __init__(self, width: int, height: int): + self.width = width + self.height = height + if width > 60: + raise ValueError("Max 60 bits wide:", width) + self.buffer = [0] * self.height * 2 + self.used = [0] * self.height * 2 + + def __repr__(self) -> str: + b = "" + for y in range(self.height): + for x in range(self.width): + if self[x, y]: + b += "X" + else: + b += "." + b += "\n" + return b + + def __getitem__(self, key: Tuple[int, int]) -> int: + x, y = key + if y > self.width: + raise ValueError() + i = 2 * x + (y // 30) + j = y % 30 + if not self.used[i] & (1 << j): + return None + return self.buffer[i] & (1 << j) + + def __setitem__(self, key: Tuple[int, int], value: int) -> None: + x, y = key + if y > self.width: + raise ValueError() + i = 2 * x + (y // 30) + j = y % 30 + if value: + self.buffer[i] |= 1 << j + else: + self.buffer[i] &= ~(1 << j) + self.used[i] |= 1 << j # buffer item was set + + +class QRBitBuffer: + """Storage class for a length of individual bits""" + + def __init__(self): + self.buffer = [] + self.length = 0 + + def __repr__(self) -> str: + return ".".join([str(n) for n in self.buffer]) + + def get(self, index: int) -> int: + """The bit value at a location""" + i = index // 8 + return self.buffer[i] & (1 << (7 - index % 8)) + + def put(self, num: int, length: int) -> None: + """Add a number of bits from a single integer value""" + for i in range(length): + self.put_bit(num & (1 << (length - i - 1))) + + def get_length_bits(self) -> int: + """Size of bit buffer""" + return self.length + + def put_bit(self, bit: int) -> None: + """Insert one bit at the end of the bit buffer""" + i = self.length // 8 + if len(self.buffer) <= i: + self.buffer.append(0) + if bit: + self.buffer[i] |= 0x80 >> (self.length % 8) + self.length += 1 diff --git a/boards/default_src/micropython/origin/build/lib/uframebuf.py b/boards/default_src/micropython/origin/build/lib/uframebuf.py index bb02c104..c3c14e87 100644 --- a/boards/default_src/micropython/origin/build/lib/uframebuf.py +++ b/boards/default_src/micropython/origin/build/lib/uframebuf.py @@ -163,6 +163,7 @@ class FrameBuffer_Base(FrameBuffer): self._buffer = buf self._way = 1 self._speed = 100 + self._miniqr = None def show(self): print("External inheritance is required to override this method") @@ -551,3 +552,20 @@ class FrameBuffer_Uincode(FrameBuffer_Base): x = buffer[1][0] * size + x + space self.show() time.sleep_ms(speed) + + def qrcode(self, data, x=0, y=0, size=None, bold=0, type=None, correct=0, color=0xffff, bg_color=0x0, sync=True): + if self._miniqr is None: + from adafruit_miniqr import QRCode + self._miniqr = QRCode + _qr = self._miniqr(qr_type=type, error_correct=correct) + _qr.add_data(data) + _qr.make() + if sync: self.fill(bg_color, sync=False) + size = min(self.height // _qr.matrix.height, self.width // _qr.matrix.width) if size is None else size + for j in range(_qr.matrix.height): + for i in range(_qr.matrix.width): + if _qr.matrix[i, j]: + self.fill_rect(x + i * size, y + j * size, int(size + bold), int(size + bold), color, sync=False) + del _qr + gc.collect() + if sync: self.show()