;=============================================================================== ; U S E R - D E F I N E D Q R C O D E C O N S T A N T S ;=============================================================================== IFNCONST QR_VERSION QR_VERSION = 2 ; 1..3, QR code size (21, 25, 29) ENDIF IFNCONST QR_LEVEL QR_LEVEL = 0 ; 0..4, error correction levels L, M, Q, H ENDIF IFNCONST QR_SINGLE_MASK QR_SINGLE_MASK = 0 ; 0|1, use only 1 of the 8 mask pattern ENDIF IFNCONST QR_PADDING QR_PADDING = 1 ; 0|1, add padding bytes add the end of test message text ENDIF IFNCONST QR_GENERATE QR_GENERATE = 0 ; 0|1, generate Reed-Solomon ECC generator polynomial on-the-fly ENDIF ;=============================================================================== ; C A L C U L A T E D Q R C O D E C O N S T A N T S ;=============================================================================== ; Do NOT change the following constants! IFNCONST QR_OVERLAP QR_OVERLAP = 0 ENDIF IFNCONST QR_SINGLE_MASK QR_SINGLE_MASK = 0 ENDIF IFNCONST QR_DIRECT_DRAW QR_DIRECT_DRAW = 0 ENDIF IF QR_VERSION = 1 ; 21x21 QR code IF QR_LEVEL = 0 QR_DEGREE = 7 ; for version 1, level L QR codes ENDIF IF QR_LEVEL = 1 QR_DEGREE = 10 ; for version 1, level M QR codes ENDIF IF QR_LEVEL = 2 QR_DEGREE = 13 ; for version 1, level Q QR codes ENDIF IF QR_LEVEL = 3 QR_DEGREE = 17 ; for version 1, level H QR codes ENDIF ENDIF IF QR_VERSION = 2 ; 25x25 QR code IF QR_LEVEL = 0 QR_DEGREE = 10 ; for version 2, level L QR codes ENDIF IF QR_LEVEL = 1 QR_DEGREE = 16 ; for version 2, level M QR codes ENDIF IF QR_LEVEL = 2 QR_DEGREE = 22 ; for version 2, level Q QR codes ENDIF IF QR_LEVEL = 3 QR_DEGREE = 28 ; for version 2, level H QR codes ENDIF ENDIF IF QR_VERSION = 3 ; 29x29 QR code IF QR_LEVEL = 0 QR_DEGREE = 15 ; for version 3, level L QR codes ENDIF IF QR_LEVEL = 1 QR_DEGREE = 26 ; for version 3, level M QR codes ENDIF IF QR_LEVEL = 2 || QR_LEVEL = 3 ECHO "" ECHO "ERROR: Version 3, Level", [QR_LEVEL]d, "not supported" ERR ENDIF ENDIF QR_SIZE = 17 + QR_VERSION * 4 ; Calculate capacity based on version _QR_VAL SET (QR_VERSION * 16 + 128) * QR_VERSION + 64 IF QR_VERSION >= 2 _QR_NUM_ALIGN = QR_VERSION / 7 + 2 _QR_VAL SET _QR_VAL - ((25 * _QR_NUM_ALIGN - 10) * _QR_NUM_ALIGN - 55) IF QR_VERSION >= 7 _QR_VAL SET _QR_VAL - 36 ENDIF ENDIF QR_CAPACITY = _QR_VAL / 8 QR_MAX_DATA = QR_CAPACITY - QR_DEGREE QR_MODE = %0100 ; byte mode QR_POLY = $11d ; GF(2^8) is based on 9 bit polynomial ; x^8 + x^4 + x^3 + x^2 + 1 = 0x11d QR_FORMATS = 15 ; 15 type information bits QR_MAX_MSG = QR_MAX_DATA - 2 QR_TOTAL = QR_MAX_DATA + QR_DEGREE ; e.g. 44 ;=============================================================================== ; V A R I A B L E S ;=============================================================================== qrRemainder = qrData ; (QR_DEGREE = e.g. 16 bytes) qrMsgData = qrData + QR_DEGREE ; (QR_MAX_DATA = e.g. 28 bytes) qrMsgIdx = qrTmpVars + 3 ;=============================================================================== ; Q R C O D E M A C R O S ;=============================================================================== ; The following code has been partially converted from the C code of the ; QR code generator found at https://github.com/nayuki/QR-Code-generator ;----------------------------------------------------------- ; Returns the product of the two given field elements modulo GF(2^8/0x11D). ; All inputs are valid. MAC _RS_MULT ;----------------------------------------------------------- ; Russian peasant multiplication (x * y) ; Input: A = x, Y = y ; Result: A .x = qrTmpVars .y = qrTmpVars+1 sta .x sty .y ; uint8_t z = 0; lda #0 ; for (int i = 7; i >= 0; i--) { ldy #7 .loopI ; z = (uint8_t)((z << 1) ^ ((z >> 7) * 0x11D)); asl bcc .skipEorPoly eor #> i) & 1) * x; asl .y bcc .skipEorX eor .x .skipEorX ; } dey bpl .loopI ENDM IF QR_GENERATE ; Computes a Reed-Solomon ECC generator polynomial for degree 16, storing in result[0 : 16-1]. ; This is implemented as a lookup table too (Generator) ;----------------------------------------------------------- MAC _RS_DIVISOR ;----------------------------------------------------------- ; E.g. g(x)=(x+1)(x+?)(x+?^2)(x+?^3)...(x+?^15) ; = x^16+3Bx^15+0Dx^14+68x^13+BDx^12+44x^11+d1x^10+1e^x9+08x^8 ; +A3x^7+41x^6+29x^5+E5x^4+62x^3+32x^2+24x+3B .root = qrTmpVars+2 .i = qrTmpVars+3 ; memset(qrGenerator, 1, 16); ldx #QR_DEGREE-1 stx .i ldy #0 .loopClear sty qrGenerator,x dex bne .loopClear ; qrGenerator[0] = 1; // Start off with the monomial x^0 iny sty qrGenerator ; uint8_t root = 1; sty .root ; for (int i = 0; i < degree; i++) { .loopI ; // Multiply the current product by (x - r^i) ; for (int j = degree-1; j >= 0; j--) { ldx #QR_DEGREE-1 .loopJ ; qrGenerator[j] = reedSolomonMultiply(qrGenerator[j], root); lda qrGenerator,x ldy .root jsr RSMult ; if (j) dex bmi .skipEor ; qrGenerator[j] ^= qrGenerator[j - 1]; eor qrGenerator,x .skipEor sta qrGenerator+1,x txa bpl .loopJ ; root = reedSolomonMultiply(root, 0x02); lda .root ldy #$02 jsr RSMult sta .root dec .i bpl .loopI ENDM ;----------------------------------------------------------- RSMult SUBROUTINE _RS_MULT rts ;----------------------------------------------------------- ENDIF ; /QR_GENERATE ;----------------------------------------------------------- MAC _RS_REMAINDER ;----------------------------------------------------------- .i = qrTmpVars+2 .factor = qrTmpVars+3 ; memset(result, 0, 16); // done in START_TEXT ; for (int i = dataLen-1; i >= 0; i--) { // Polynomial division ldx #QR_MAX_DATA-1 .loopI stx .i ; uint8_t factor = qrMsgData[i] ^ qrRemainder[degree - 1]; lda qrMsgData,x eor qrRemainder + QR_DEGREE - 1 sta .factor ; memmove(&qrRemainder[1], &qrRemainder[0], (size_t)(16 - 1) * sizeof(qrRemainder[0])); ldx #QR_DEGREE-1 .loopMove lda qrRemainder-1,x sta qrRemainder,x dex bne .loopMove ; qrRemainder[0] = 0; lda #0 sta qrRemainder ; for (int j = 16-1; j >= 0; j--) ldx #QR_DEGREE-1 .loopJ ; qrRemainder[j] ^= reedSolomonMultiply(generator[j], factor); ldy .factor IF QR_GENERATE lda qrGenerator,x jsr RSMult ELSE lda Generator,x _RS_MULT ENDIF eor qrRemainder,x sta qrRemainder,x ; } dex bpl .loopJ ; } ldx .i dex bpl .loopI ENDM IF QR_DIRECT_DRAW = 0 ;----------------------------------------------------------- MAC _BLACK_FUNC ;----------------------------------------------------------- ; Blacks all function/alignment and timing pattern areas ; assume bitmap is clear, only draw the pattern ldy #4+2 ; pattern + timing lines .loopPattern lda #$ff ; fill pattern jsr DrawPattern bpl .loopPattern ENDM ;----------------------------------------------------------- BlackFunc SUBROUTINE ;----------------------------------------------------------- _BLACK_FUNC rts ;----------------------------------------------------------- MAC _DRAW_FUNC ;----------------------------------------------------------- ; Draws all function/alignment and timing pattern over existing codewords ; blacken functions pattern first jsr BlackFunc ; draw function pattern ldy #4 .loopPattern lda #$00 ; draw pattern jsr DrawPattern bne .loopPattern ; draw horizontal timing pattern ldy #QR_SIZE-1 - 9 ldx #QR_SIZE-1 - 6 .loopTimingH jsr InvertPixel dey dey cpy #9 bcs .loopTimingH ; draw vertical timing pattern ldy #6 ldx #QR_SIZE-1 - 9 .loopTimingV jsr InvertPixel dex dex cpx #9 bcs .loopTimingV ENDM ; ;--------------------------------------------------------------- DrawPattern SUBROUTINE ;--------------------------------------------------------------- ; Y = index, A = fill .index = qrTmpVars .width = qrTmpVars+1 .height = qrTmpVars+2 .offset = qrTmpVars+3 .tmpPat = qrTmpVars+4 .fill = qrTmpVars+5 sty .index sta .fill ldx PatternY,y lda PatternHeight,y sta .height lda PatternOffset,y tay .loopRow sty .offset lda PatternStart,y ora .fill sta .tmpPat ldy .index lda PatternWidth,y sta .width lda PatternX,y tay ; draw one row .loopBit sec ; allows for >8 black pixel ror .tmpPat bcc .clear ;.set jsr CheckPixel bne .skipInvert .invert jsr InvertPixel .skipInvert iny ; x++ dec .width bne .loopBit dex ; y-- ldy .offset iny dec .height bne .loopRow .exit ldy .index dey rts .clear jsr CheckPixel bne .invert beq .skipInvert ENDIF ; /QR_DIRECT_DRAW = 0 ;----------------------------------------------------------- ; Draws the raw codewords (including data and ECC) onto the given QR Code. This requires the initial state of ; the QR Code to be black at function modules and white at codeword modules (including unused remainder bits). MAC _DRAW_CODEWORDS ;----------------------------------------------------------- ; Note: This part has the maximum RAM usage .vert = qrTmpVars+0 .j = qrTmpVars+1 .y = qrTmpVars+2 IF QR_DIRECT_DRAW .iBit = qrTmpVars+3 .iByte = qrTmpVars+4 .right1 = qrTmpVars+5 ELSE ; must not overlap with DrawPattern space .iBit = qrTmpVars+6 .iByte = qrTmpVars+7 .right1 = qrTmpVars+8 ENDIF ; blacken the (right) function modules in the bitmap IF QR_OVERLAP _BLACK_RIGHT ; returns with X = 0 ELSE IF QR_DIRECT_DRAW _BLACK_FUNC ; returns with X = 0 ELSE jsr BlackFunc ldx #0 ENDIF ENDIF ; int i = 0; // Bit index into the data ; ldx #0 ; 2600 code has data in reversed order stx .iBit lda #QR_TOTAL-1 sta .iByte ; // Do the funny zigzag scan ; Note: 2600 code has .right1 increased by 1 ; for (int right = qrsize - 1; right >= 1; right -= 2) { // Index of right column in each column pair ldy #QR_SIZE-1+1 .loopRight ; if (right == 6) cpy #6+1 bne .not6 ; right = 5; dey ; skip the timing column .not6 sty .right1 IF QR_OVERLAP ; overwrite shared data cpy #16+1 bne .skipBlackMiddle ; blacken the middle function modules in the bitmap _BLACK_MIDDLE IF QR_DIRECT_DRAW = 0 ldy .right1 ; DrawPattern overwrites Y ENDIF .skipBlackMiddle cpy #8+1 bne .skipBlackLeft ; blacken the left function modules in the bitmap _BLACK_LEFT .skipBlackLeft ENDIF ; for (int vert = 0; vert < qrsize; vert++) { // Vertical counter ldy #QR_SIZE-1 .loopVert sty .vert ; bool upward = ((right + 1) & 2) != 0; // 2600 code works in reverse lda .right1 and #$02 bne .notUp ; int y = upward ? qrsize - 1 - vert : vert; // Actual y coordinate lda #QR_SIZE-1;+1 sec sbc .vert tay .notUp sty .y ; for (int j = 0; j < 2; j++) { ; some tricky code with .j here ldy .right1 BIT_B .loopJ dey sty .j ; int x = right - j; // Actual x coordinate dey ; if (!getModule(qrcode, x, y) && i < dataLen * 8) { ; ldy .x ldx .y jsr CheckPixel bne .skipPixel ; bool black = getBit(qrData[i >> 3], 7 - (i & 7)); ldx .iByte lda qrData,x ldx .iBit and BitMask,x beq .skipInv ; setModule(qrcode, x, y, black); ; ldy .x ldx .y jsr InvertPixel ldx .iBit .skipInv ; i++; inx txa and #$07 sta .iBit bne .skipByte dec .iByte bmi .exitDraw ; 2600 code exits here! .skipByte ; } .skipPixel ldy .j cpy .right1 beq .loopJ ; } // for j ldy .vert dey bpl .loopVert ; } // for vert ldy .right1 dey dey IF QR_OVERLAP jmp .loopRight ELSE bpl .loopRight ; unconditional! ENDIF ; } // for right .exitDraw ENDM ;----------------------------------------------------------- MAC _APPLY_MASK ;----------------------------------------------------------- IF QR_SINGLE_MASK .y = qrTmpVars ldx #QR_SIZE - 1 .loopY stx .y ldy #QR_SIZE - 1 .loopX ; 0: (x + y) % 2 == 0 tya eor .y lsr bcs .skipInvert jsr InvertPixel .skipInvert dey bpl .loopX dex bpl .loopY ELSE .y = qrTmpVars ;.x = qrTmpVars+2 .xMod3 = qrTmpVars+1 .yMod3 = qrTmpVars+2 .xDiv3 = qrTmpVars+3 .tmp = qrTmpVars+4 lda #0 sta .yMod3 ldx #QR_SIZE - 1 .loopY stx .y lda #0 sta .xMod3 sta .xDiv3 ldy #QR_SIZE - 1 .loopX ; sty .x lda qrPattern bne .not0 ; 0: (x + y) % 2 == 0 tya eor .y bpl .checkMod2 .not0 cmp #4 bne .not4 ; 4: (x / 3 + y / 2) % 2 == 0 lda .y lsr adc .xDiv3 bpl .checkMod2 .not4 bcs .above4 lsr bcs .not2 ; 2: x % 3 == 0 lda .xMod3 beq .invert bne .skipInvert .not2 bne .is3 ; 1: y % 2 == 0 txa bpl .checkMod2 .is3 ; 3: (x + y) % 3 == 0 lda .xMod3 ; sec sbc .yMod3 beq .invert bne .skipInvert .above4 cmp #6 beq .is6 bcs .is7 .is6 php ; 5: x * y % 2 + x * y % 3 == 0 ; 6: (x * y % 2 + x * y % 3) % 2 == 0 lda .xMod3 beq .modEven56 lda .yMod3 beq .modEven56 clc adc .xMod3 BIT_W .modEven56 lda #0 sta .tmp tya lsr bcc .even56 txa lsr bcc .even56 inc .tmp .even56 plp lda .tmp bcs .checkMod2 beq .invert bne .skipInvert .is7 ; 7: ((x + y) % 2 + x * y % 3) % 2 == 0 tya eor .y sta .tmp lda .xMod3 beq .modEven7 lda .yMod3 beq .modEven7 clc adc .xMod3 adc .tmp sta .tmp .modEven7 lda .tmp .checkMod2 lsr bcs .skipInvert .invert jsr InvertPixel .skipInvert ; next X dec .xMod3 bpl .xMod3OK lda #2 sta .xMod3 inc .xDiv3 .xMod3OK dey bpl .loopX ; next Y dec .yMod3 bpl .yMod3OK lda #2 sta .yMod3 .yMod3OK dex bmi .exitLoopY jmp .loopY .exitLoopY ENDIF ; !QR_SINGLE_MASK ENDM ;----------------------------------------------------------- MAC _DRAW_FORMAT ;----------------------------------------------------------- IF QR_SINGLE_MASK = 0 || QR_DIRECT_DRAW = 0 .idx = qrTmpVars ldy #QR_FORMATS-1 .loopFormat sty .idx cpy #8 IF QR_SINGLE_MASK ldx #0 ELSE ldx qrPattern ENDIF lda FormatLo,x and BitMask,y bcc .lowFormat lda FormatHi,x and BitMask-8,y .lowFormat IF QR_DIRECT_DRAW beq .skipFormat ELSE bne .skipFormat ENDIF ldx FormatY1,y lda FormatX1,y tay jsr InvertPixel ldy .idx ldx FormatY2,y lda FormatX2,y tay jsr InvertPixel ldy .idx .skipFormat dey bpl .loopFormat ENDIF ENDM ; ********** The user macros start here: ********** ;----------------------------------------------------------- MAC START_MSG ;----------------------------------------------------------- ; A = message length ; add mode and length to message data tax lsr lsr lsr lsr ora #(QR_MODE << 4) ; (QR_MODE << 4) | (MSG_LEN >> 4) sta qrMsgData + QR_MAX_DATA - 1 txa asl asl asl asl ; (MSG_LEN << 4) sta qrMsgData + QR_MAX_DATA - 2 lda #QR_MAX_DATA - 3 sta qrMsgIdx ; clear the remaining data buffer ldx #QR_TOTAL-3 lda #0 .loopClear sta qrData,x dex bpl .loopClear ENDM ;--------------------------------------------------------------- MAC ADD_MSG_BYTE ;--------------------------------------------------------------- ; A = byte to add ldx qrMsgIdx pha lsr lsr lsr lsr ora qrMsgData + 1,x sta qrMsgData + 1,x pla asl asl asl asl sta qrMsgData,x dec qrMsgIdx ENDM ;----------------------------------------------------------- MAC STOP_MSG ;----------------------------------------------------------- IF QR_PADDING .msgLen = qrTmpVars ; pad with optional filler bytes (QR code works without too) lda #QR_MAX_MSG - 1 sec sbc .msgLen bcc .noPadding tax .loopPadding lda #$ec ; defined by QR standard sta qrMsgData,x dex bmi .noPadding lda #$11 ; defined by QR standard sta qrMsgData,x dex bpl .loopPadding .noPadding ENDIF ENDM ;----------------------------------------------------------- MAC GEN_QR_CODE ;----------------------------------------------------------- ; This is the main macro to use! QRCodeCode IF QR_GENERATE ; generate the Reed-Solomon ECC generator polynomial RSDevisor _RS_DIVISOR ENDIF ; calculate the ECC RSRemainder _RS_REMAINDER ; draw the code words onto the bitmap DrawCodes _DRAW_CODEWORDS ; apply the pattern mask ApplyMask _APPLY_MASK ; blacken the function modules in the bitmap again ; and draw the function modules in the bitmap DrawFunc _DRAW_FUNC ; draw the format bits DrawFormat _DRAW_FORMAT ECHO "QR Code encoding code:", [. - QRCodeCode]d, "bytes" _QR_TOTAL SET _QR_TOTAL + . - QRCodeCode ENDM ;----------------------------------------------------------- MAC QR_CODE_DATA ;----------------------------------------------------------- ; Add this to your code's data area QRCodeData IF QR_DIRECT_DRAW = 0 ; Function pattern parameters PatternX ; left .byte 6 ; left, vertical timing line .byte 0, 0, QR_SIZE-8 ; eye pattern .byte QR_SIZE-8, QR_SIZE-9 ; alignment pattern (right/middle part) .byte 9 ; top, horizontal timing line PatternY ; top .byte QR_SIZE - 10 ; left, vertical timing line .byte QR_SIZE-1, 7, QR_SIZE-1 ; eye pattern .byte 8, 8 ; alignment pattern (right/middle part) .byte QR_SIZE - 7 ; top, horizontal timing line PatternOffset = . - 1 .byte EyeLeftTop-PatternStart ; 1 .byte EyeLeftBottom-PatternStart ; 2 .byte EyeRightTop-PatternStart ; 3 .byte AlignRightBottom-PatternStart .byte AlignRightBottom-PatternStart ; timing lines need no pattern, always drawn filled here PatternWidth .byte 1 ; left, vertical timing line .byte 9, 9, 8 ; eye pattern .byte 4, 1 ; alignment pattern (right/middle part) ; .byte QR_SIZE - 9 - 8 ; top, horizontal timing line PatternHeight .byte QR_SIZE - 9 - 8 ; left, vertical timing line .byte 9, 8, 9 ; eye pattern .byte 5, 5 ; alignment pattern (right/middle part) .byte 1 ; top, horizontal timing line PatternStart EyeRightTop .byte %11111110 .byte %10000010 .byte %10111010 .byte %10111010 .byte %10111010 .byte %10000010 .byte %11111110 .byte %00000000 .byte %11111111 AlignRightBottom = . - 1 ; .byte %1111 .byte %1000 .byte %1010 .byte %1000 .byte %1111 EyeLeftBottom .byte %00000000 ; .byte %01111111 ; .byte %01000001 ; .byte %01011101 ; .byte %01011101 ; .byte %01011101 ; .byte %01000001 ; .byte %01111111 EyeLeftTop .byte %01111111 .byte %01000001 .byte %01011101 .byte %01011101 .byte %01011101 .byte %01000001 .byte %01111111 .byte %00000000 .byte %11111111 ENDIF ; /QR_DIRECT_DRAW ; Format Information Strings IF QR_SINGLE_MASK = 0 || QR_DIRECT_DRAW = 0 IF QR_LEVEL = 0 ; L FormatLo .byte %11101111 .byte %11100101 .byte %11111011 .byte %11110001 .byte %11001100 .byte %11000110 .byte %11011000 .byte %11010010 FormatHi .byte %10001000 .byte %11100110 .byte %01010100 .byte %00111010 .byte %01011110 .byte %00110000 .byte %10000010 .byte %11101100 ENDIF IF QR_LEVEL = 1 ; M FormatLo .byte %10101000 .byte %10100010 .byte %10111100 .byte %10110110 .byte %10001011 .byte %10000001 .byte %10011111 .byte %10010101 FormatHi .byte %00100100 .byte %01001010 .byte %11111000 .byte %10010110 .byte %11110010 .byte %10011100 .byte %00101110 .byte %01000000 ENDIF IF QR_LEVEL = 2 ; Q FormatLo .byte %01101010 .byte %01100000 .byte %01111110 .byte %01110100 .byte %01001001 .byte %01000011 .byte %01011101 .byte %01010111 FormatHi .byte %10111110 .byte %11010000 .byte %01100010 .byte %00001100 .byte %01101000 .byte %00000110 .byte %10110100 .byte %11011010 ENDIF IF QR_LEVEL = 3 ; H FormatLo .byte %00101101 .byte %00100111 .byte %00111001 .byte %00110011 .byte %00001110 .byte %00000100 .byte %00011010 .byte %00010000 FormatHi .byte %00010010 .byte %01111100 .byte %11001110 .byte %10100000 .byte %11000100 .byte %10101010 .byte %00011000 .byte %01110110 ENDIF ; positions of the 15 type information bits FormatX1 .byte 0, 1, 2, 3, 4, 5, 7, 8 ; ds 7, 8 ; shared FormatX2 ds 7, 8 .byte QR_SIZE-8, QR_SIZE-7, QR_SIZE-6, QR_SIZE-5 .byte QR_SIZE-4, QR_SIZE-3, QR_SIZE-2, QR_SIZE-1 FormatY2 .byte 0, 1, 2, 3, 4, 5, 6 ; ds 8, QR_SIZE-9 ; shared FormatY1 ds 8, QR_SIZE-9 .byte QR_SIZE-8, QR_SIZE-6, QR_SIZE-5, QR_SIZE-4 .byte QR_SIZE-3, QR_SIZE-2, QR_SIZE-1 ENDIF ; /QR_SINGLE_MASK = 0 || QR_DIRECT_DRAW = 0 BitMask .byte $80, $40, $20, $10, $8, $4, $2, $1 IF QR_GENERATE = 0 Generator ; data in reversed order! IF QR_DEGREE = 7 .byte $75, $44, $0b, $a4, $9a, $7a, $7f ENDIF IF QR_DEGREE = 10 .byte $c1, $9d, $71, $5f, $5e, $c7, $6f, $9f .byte $c2, $d8 ENDIF IF QR_DEGREE = 13 .byte $87, $84, $53, $2b, $2e, $0d, $34, $11 .byte $b1, $11, $e3, $49, $89 ENDIF IF QR_DEGREE = 15 .byte $1a, $86, $20, $97, $84, $8b, $69, $69 .byte $0a, $4a, $70, $a3, $6f, $c4, $1d ENDIF IF QR_DEGREE = 16 ; Reed-Solomon ECC generator polynomial for degree 16 ; g(x)=(x+1)(x+?)(x+?^2)(x+?^3)...(x+?^15) ; = x^16+3bx^15+0dx^14+68x^13+bdx^12+44x^11+d1x^10+1e^x9+08x^8 ; +a3x^7+41x^6+29x^5+e5x^4+62x^3+32x^2+24x+3b .byte $3b, $24, $32, $62, $e5, $29, $41, $a3 .byte $08, $1e, $d1, $44, $bd, $68, $0d, $3b ENDIF IF QR_DEGREE = 17 .byte $4f, $63, $7d, $35, $55, $86, $8f, $29 .byte $f9, $53, $c5, $16, $77, $78, $53, $42 .byte $77 ENDIF IF QR_DEGREE = 22 .byte $f5, $91, $1a, $e6, $da, $56, $fd, $43 .byte $7b, $1d, $89, $1c, $28, $45, $bd, $13 .byte $f4, $b6, $b0, $83, $b3, $59 ENDIF IF QR_DEGREE = 26 .byte $5e, $2b, $4d, $92, $90, $46, $44, $87 .byte $2a, $e9, $75, $d1, $28, $91, $18, $ce .byte $38, $4d, $98, $c7, $62, $88, $04, $b7 .byte $44, $f6 ENDIF IF QR_DEGREE = 28 .byte $c5, $3a, $4a, $b0, $93, $79, $64, $b5 .byte $7f, $e9, $77, $75, $38, $f7, $0c, $a7 .byte $29, $64, $ae, $67, $96, $d0, $fb, $12 .byte $0d, $1c, $09, $fc ENDIF QR_DEGREE = . - Generator ; verify data size ENDIF ; /QR_GENERATE ECHO "QR Code encoding data:", [. - QRCodeData]d, "bytes" _QR_TOTAL SET _QR_TOTAL + . - QRCodeData ENDM