1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author        Notes
8  */
9 #include <rtconfig.h>
10 
11 #ifdef BSP_USING_LCD_QRCODE
12 #include <qrcode.h>
13 #include "drv_lcd.h"
14 #include "lcd_qrcode.h"
15 #define DBG_TAG    "drv.lcd.qrcode"
16 #define DBG_LVL    DBG_INFO
17 #include <rtdbg.h>
18 
19 static QRCode qrcode;
20 
get_enlargement_factor(rt_uint16_t x,rt_uint16_t y,rt_uint8_t size)21 static rt_uint8_t get_enlargement_factor(rt_uint16_t x, rt_uint16_t y, rt_uint8_t size)
22 {
23     rt_uint8_t enlargement_factor = 1 ;
24 
25     if (x + size * 8 <= LCD_W && y + size * 8 <= LCD_H)
26     {
27         enlargement_factor = 8;
28     }
29     else if (x + size * 4 <= LCD_W &&y + size * 4 <= LCD_H)
30     {
31         enlargement_factor = 4;
32     }
33     else if (x + size * 2 <= LCD_W && y + size * 2 <= LCD_H)
34     {
35         enlargement_factor = 2;
36     }
37 
38     return enlargement_factor;
39 }
40 
show_qrcode_by_point(rt_uint16_t x,rt_uint16_t y,rt_uint8_t size,rt_uint8_t enlargement_factor)41 static void show_qrcode_by_point(rt_uint16_t x, rt_uint16_t y, rt_uint8_t size, rt_uint8_t enlargement_factor)
42 {
43     rt_uint32_t width = 0, high = 0;
44     for (high = 0; high < size; high++)
45     {
46         for (width = 0; width < size; width++)
47         {
48             if (qrcode_getModule(&qrcode, width, high))
49             {
50                 /* magnify pixel */
51                 for (rt_uint32_t offset_y = 0; offset_y < enlargement_factor; offset_y++)
52                 {
53                     for (rt_uint32_t offset_x = 0; offset_x < enlargement_factor; offset_x++)
54                     {
55                         lcd_draw_point(x + enlargement_factor * width + offset_x, y + enlargement_factor * high + offset_y);
56                     }
57                 }
58             }
59         }
60     }
61 }
62 
show_qrcode_by_line(rt_uint16_t x,rt_uint16_t y,rt_uint8_t size,rt_uint8_t enlargement_factor,rt_uint8_t * qrcode_buf)63 static void show_qrcode_by_line(rt_uint16_t x, rt_uint16_t y, rt_uint8_t size, rt_uint8_t enlargement_factor,rt_uint8_t *qrcode_buf)
64 {
65     rt_uint32_t width = 0, high = 0;
66     for (high = 0; high < qrcode.size; high++)
67     {
68         for (width = 0; width < qrcode.size; width++)
69         {
70             if (qrcode_getModule(&qrcode, width, high))
71             {
72                 /* magnify pixel */
73                 for (rt_uint32_t offset_y = 0; offset_y < enlargement_factor; offset_y++)
74                 {
75                     for (rt_uint32_t offset_x = 0; offset_x < enlargement_factor; offset_x++)
76                     {
77                         /* save the information of modules */
78                         qrcode_buf[2 * (enlargement_factor * width + offset_x + offset_y * qrcode.size * enlargement_factor)] = FORE_COLOR >> 8;
79                         qrcode_buf[2 * (enlargement_factor * width + offset_x + offset_y * qrcode.size * enlargement_factor) + 1] = FORE_COLOR;
80                     }
81                 }
82             }
83             else
84             {
85                 /* magnify pixel */
86                 for (rt_uint32_t offset_y = 0; offset_y < enlargement_factor; offset_y++)
87                 {
88                     for (rt_uint32_t offset_x = 0; offset_x < enlargement_factor; offset_x++)
89                     {
90                         /* save the information of blank */
91                         qrcode_buf[2 * (enlargement_factor * width + offset_x + offset_y * qrcode.size * enlargement_factor)] = BACK_COLOR >> 8;
92                         qrcode_buf[2 * (enlargement_factor * width + offset_x + offset_y * qrcode.size * enlargement_factor) + 1] = BACK_COLOR;
93                     }
94                 }
95             }
96         }
97         /* display a line of qrcode */
98         lcd_show_image(x, y + high * enlargement_factor, qrcode.size * enlargement_factor, enlargement_factor, qrcode_buf);
99     }
100 }
101 
102 /**
103  * display the qrcode on the lcd.
104  * size = (4 * version +17) * enlargement
105  *
106  * @param   x           x position
107  * @param   y           y position
108  * @param   version     version of qrcode (ECC_LOW, ECC_MEDIUM, ECC_QUARTILE or ECC_HIGH)
109  * @param   ecc         level of error correction
110  * @param   data        string
111  * @param   enlargement enlargement_factor
112  *
113  * @return   0: display success
114  *          -1: generate qrcode failed
115 *           -5: memory low
116  */
lcd_show_qrcode(rt_uint16_t x,rt_uint16_t y,rt_uint8_t version,rt_uint8_t ecc,const char * data,rt_uint8_t enlargement)117 rt_err_t lcd_show_qrcode(rt_uint16_t x, rt_uint16_t y, rt_uint8_t version, rt_uint8_t ecc, const char *data, rt_uint8_t enlargement)
118 {
119     RT_ASSERT(data);
120 
121     rt_int8_t result = 0;
122     rt_uint8_t enlargement_factor = 1;
123     rt_uint8_t *qrcode_buf = RT_NULL;
124 
125     if (x + version * 4 + 17 > LCD_W || y + version * 4 + 17 > LCD_H)
126     {
127         LOG_E("The qrcode is too big!");
128         return -RT_ERROR;
129     }
130 
131     rt_uint8_t *qrcodeBytes = (rt_uint8_t *)rt_calloc(1, qrcode_getBufferSize(version));
132     if (qrcodeBytes == RT_NULL)
133     {
134         LOG_E("no memory for qrcode!");
135         return -RT_ENOMEM;
136     }
137 
138     /* generate qrcode */
139     result = qrcode_initText(&qrcode, qrcodeBytes, version, ecc, data);
140     if (result >= 0)
141     {
142         /* set enlargement factor */
143         if(enlargement == 0)
144         {
145             enlargement_factor = get_enlargement_factor(x, y, qrcode.size);
146         }
147         else
148         {
149             enlargement_factor = enlargement;
150         }
151 
152         /* malloc memory for quick display of qrcode */
153         qrcode_buf = rt_malloc(qrcode.size * 2 * enlargement_factor * enlargement_factor);
154         if (qrcode_buf == RT_NULL)
155         {
156             /* clear lcd */
157             lcd_fill(x, y, x + qrcode.size, y + qrcode.size, BACK_COLOR);
158 
159             /* draw point to display qrcode */
160             show_qrcode_by_point(x, y, qrcode.size, enlargement_factor);
161         }
162         else
163         {
164             /* quick display of qrcode */
165             show_qrcode_by_line(x, y, qrcode.size, enlargement_factor,qrcode_buf);
166         }
167         result = RT_EOK;
168     }
169     else
170     {
171         LOG_E("QRCODE(%s) generate falied(%d)\n", data, result);
172         result = -RT_ENOMEM;
173         goto __exit;
174     }
175 
176 __exit:
177     if (qrcodeBytes)
178     {
179         rt_free(qrcodeBytes);
180     }
181 
182     if (qrcode_buf)
183     {
184         rt_free(qrcode_buf);
185     }
186 
187     return result;
188 }
189 #endif /* BSP_USING_LCD_QRCODE */
190