1 /*
2  * Copyright (C) 2015-2021 Alibaba Group Holding Limited
3  */
4 
5 #include "sh1106.h"
6 #include "aos/hal/gpio.h"
7 #include "aos/hal/spi.h"
8 #include "hal_iomux_haas1000.h"
9 #include "ulog/ulog.h"
10 #include "sh1106_hdconfig.h"
11 #include <math.h>
12 #include <stdio.h>
13 #include <time.h>
14 
15 #if USE_SOFT_SPI == 1
16 #include <sys/ioctl.h>
17 #include <vfsdev/gpio_dev.h>
18 #include <drivers/char/u_device.h>
19 #include <drivers/u_ld.h>
20 #include "aos/vfs.h"
21 static int fd = 0;
22 #endif
23 
24 #define OLED_PAGE_SIZES 132
25 #define SPI_MAX_BLOCK 60000
26 
27 #define PI 3.1415926535
28 
29 uint8_t OLED_GRAM[8][OLED_PAGE_SIZES];
30 uint8_t oled_remote_buffer[8 * OLED_PAGE_SIZES * 2];
31 
32 static spi_dev_t  spi_sh1106 = {0};
33 static gpio_dev_t gpio_sh1106_dc;
34 static gpio_dev_t gpio_sh1106_reset;
35 
36 struct timeval tv;
37 
38 #if USE_SOFT_SPI == 0
spi_write(const void * data,uint32_t size)39 static inline void spi_write(const void *data, uint32_t size)
40 {
41     if (size > SPI_MAX_BLOCK) {
42         uint32_t rest  = size;
43         uint32_t start = 0;
44         while (rest > SPI_MAX_BLOCK) {
45             hal_spi_send(&spi_sh1106, (const void *)(data + start),
46                          SPI_MAX_BLOCK, 10);
47             start += SPI_MAX_BLOCK;
48             rest -= SPI_MAX_BLOCK;
49         }
50         hal_spi_send(&spi_sh1106, (const void *)(data + start), rest, 10);
51     } else {
52         hal_spi_send(&spi_sh1106, (const void *)data, (uint16_t)size, 10);
53     }
54 }
OLED_GPIO_Init()55 static inline int OLED_GPIO_Init()
56 {
57     // printf("hardware_init START\r\n");
58 
59     gpio_sh1106_dc.port   = SPI1_DC_PIN;
60     gpio_sh1106_dc.config = OUTPUT_PUSH_PULL;
61     hal_gpio_init(&gpio_sh1106_dc);
62 
63     gpio_sh1106_reset.port   = SPI1_RESET_PIN;
64     gpio_sh1106_reset.config = OUTPUT_PUSH_PULL;
65     hal_gpio_init(&gpio_sh1106_reset);
66 
67     hal_gpio_output_high(&gpio_sh1106_dc);
68 
69     hal_gpio_output_low(&gpio_sh1106_reset);
70     aos_msleep(1000);
71     hal_gpio_output_high(&gpio_sh1106_reset);
72 
73     // printf("hal_gpio_init done\r\n");
74     return 0;
75 }
76 
OLED_SPI_Init()77 static inline int OLED_SPI_Init()
78 {
79     spi_sh1106.port              = 1;
80     spi_sh1106.config.mode       = SPI_WORK_MODE_3; // CPOL = 1; CPHA = 1
81     spi_sh1106.config.freq       = 26000000;
82     spi_sh1106.config.role       = SPI_ROLE_MASTER;
83     spi_sh1106.config.firstbit   = SPI_FIRSTBIT_MSB;
84     spi_sh1106.config.t_mode     = SPI_TRANSFER_NORMAL;
85     spi_sh1106.config.serial_len = 8;
86     spi_sh1106.config.data_size  = SPI_DATA_SIZE_8BIT;
87     spi_sh1106.config.cs         = SPI_CS_DIS;
88 
89     hal_spi_init(&spi_sh1106);
90     printf("hal_spi_init done\r\n");
91     return 0;
92 }
93 
write_command(uint8_t c)94 static inline void write_command(uint8_t c)
95 {
96     hal_gpio_output_low(&gpio_sh1106_dc);
97     spi_write(&c, sizeof(c));
98     hal_gpio_output_high(&gpio_sh1106_dc);
99 }
100 
write_data(uint8_t d)101 static inline void write_data(uint8_t d)
102 {
103     hal_gpio_output_high(&gpio_sh1106_dc);
104     spi_write(&d, sizeof(d));
105     hal_gpio_output_high(&gpio_sh1106_dc);
106 }
107 
write_data_page(uint8_t * data,uint16_t size)108 static inline void write_data_page(uint8_t *data, uint16_t size)
109 {
110     uint8_t i;
111     hal_gpio_output_high(&gpio_sh1106_dc);
112     spi_write(data, size);
113 }
114 #else
OLED_GPIO_Init()115 static inline int OLED_GPIO_Init()
116 {
117     gpio_dev_t oled_gpio;
118 
119     // 对各个PIN进行初始化
120     oled_gpio.port   = OLED_CLK_PIN;
121     oled_gpio.config = OUTPUT_PUSH_PULL;
122     hal_gpio_init(&oled_gpio);
123 
124     oled_gpio.port   = OLED_SDA_PIN;
125     oled_gpio.config = OUTPUT_PUSH_PULL;
126     hal_gpio_init(&oled_gpio);
127 
128     oled_gpio.port   = OLED_RES_PIN;
129     oled_gpio.config = OUTPUT_PUSH_PULL;
130     hal_gpio_init(&oled_gpio);
131 
132     oled_gpio.port   = OLED_DC_PIN;
133     oled_gpio.config = OUTPUT_PUSH_PULL;
134     hal_gpio_init(&oled_gpio);
135 
136     OLED_DC(1);
137     /* 复位 */
138     OLED_RES(0);
139     aos_msleep(1000);
140     OLED_RES(1);
141 
142     fd = open("/dev/gpio", 0);
143     printf("open gpio %s, fd:%d\r\n", fd >= 0 ? "success" : "fail", fd);
144     return 0;
145 }
146 
OLED_GPIO_Set(unsigned char port,unsigned char leve)147 static void OLED_GPIO_Set(unsigned char port, unsigned char leve)
148 {
149     struct gpio_io_config config;
150 
151     config.id = port;
152     config.config = GPIO_IO_OUTPUT | GPIO_IO_OUTPUT_PP;
153     if (leve == 1) {
154         config.data = 1;
155     } else if (leve == 0) {
156         config.data = 0;
157     } else {
158         return;
159     }
160     ioctl(fd, IOC_GPIO_SET, (unsigned long)&config);
161 }
162 
OLED_SCLK(uint8_t x)163 void OLED_SCLK(uint8_t x)
164 {
165     if (x == 1) {
166         OLED_GPIO_Set(OLED_CLK_PIN, 1);
167     } else if (x == 0) {
168         OLED_GPIO_Set(OLED_CLK_PIN, 0);
169     }
170 }
171 
OLED_RES(uint8_t x)172 void OLED_RES(uint8_t x)
173 {
174     if (x == 1) {
175         OLED_GPIO_Set(OLED_RES_PIN, 1);
176     } else if (x == 0) {
177         OLED_GPIO_Set(OLED_RES_PIN, 0);
178     }
179 }
180 
OLED_DC(uint8_t x)181 void OLED_DC(uint8_t x)
182 {
183     if (x == 1) {
184         OLED_GPIO_Set(OLED_DC_PIN, 1);
185     } else if (x == 0) {
186         OLED_GPIO_Set(OLED_DC_PIN, 0);
187     }
188 }
189 
OLED_SDIN(uint8_t x)190 void OLED_SDIN(uint8_t x)
191 {
192     struct gpio_io_config config;
193 
194     config.id = OLED_SDA_PIN;
195     config.config = GPIO_IO_OUTPUT | GPIO_IO_OUTPUT_PP;
196     if (x == 0x80) {
197         config.data = 1;
198     } else if (x == 0) {
199         config.data = 0;
200     }
201     ioctl(fd, IOC_GPIO_SET, (unsigned long)&config);
202 }
203 
OLED_SPI_Init()204 static inline int OLED_SPI_Init()
205 {
206     // Nothing to do
207     return 0;
208 }
209 
write_command(uint8_t cmd)210 static inline void write_command(uint8_t cmd)
211 {
212     uint8_t i, k;
213     /*写命令拉低DC */
214     OLED_DC(0);
215 
216     for (i = 0; i < 8; i++) {
217         /* 时钟线,上升沿有效 */
218         OLED_SCLK(0);
219         k = cmd & (0x80);
220         OLED_SDIN(k);
221         OLED_SCLK(1);//high valid
222         cmd <<= 1;
223     }
224     OLED_DC(1);
225 }
226 
write_data(uint8_t data)227 static inline void write_data(uint8_t data)
228 {
229     uint8_t i, k;
230     /* 写数据拉高DC */
231     OLED_DC(1);
232 
233     for (i = 0; i < 8; i++) {
234         /* 时钟线,上升沿有效 */
235         OLED_SCLK(0);
236         k = data & (0x80);
237         OLED_SDIN(k);
238         OLED_SCLK(1);
239         data <<= 1;
240     }
241     OLED_DC(1);
242 }
243 
write_data_page(uint8_t * data,uint16_t size)244 static inline void write_data_page(uint8_t *data, uint16_t size)
245 {
246     uint8_t i, j, k, d;
247 
248     for (j = 0; j < size; j++) {
249         d = data[j];
250         for (i = 0; i < 8; i++) {
251             OLED_SCLK(0);
252             k = d & (0x80);
253             OLED_SDIN(k);
254             OLED_SCLK(1);
255             d <<= 1;
256         }
257     }
258     OLED_DC(1);
259 }
260 #endif
261 
262 #if RECORD_SCREEN == 1
zip_oled_gram(uint8_t * des,uint16_t * des_len)263 static uint16_t zip_oled_gram(uint8_t *des, uint16_t *des_len)
264 {
265     uint8_t buf = OLED_GRAM[0][0];
266     uint8_t cnt = 0;
267     *des_len    = 0;
268     for (int i = 0; i < 8; i++) {
269         for (int j = 0; j < 132; j++) {
270             if (OLED_GRAM[i][j] == buf) {
271                 cnt++;
272                 if (cnt == 0xff) {
273                     des[(*des_len)++] = buf;
274                     des[(*des_len)++] = cnt;
275                     cnt               = 0;
276                 }
277             }
278             if (OLED_GRAM[i][j] != buf) {
279                 des[(*des_len)++] = buf;
280                 des[(*des_len)++] = cnt;
281                 cnt               = 1;
282                 buf               = OLED_GRAM[i][j];
283             }
284         }
285     }
286     des[(*des_len)++] = buf;
287     des[(*des_len)++] = cnt;
288     return *des_len;
289 }
290 #endif
291 
OLED_Refresh_GRAM(void)292 void OLED_Refresh_GRAM(void)
293 {
294 #if FB_FRAME_EN == 1
295     //fb frame todo:
296 #else
297     for (uint8_t i = 0; i < 8; i++) {
298         /* 设置显示的起始地址 */
299         write_command(0xB0 + i); // 设置页地址(行)
300         write_command(0x00);     // 设置列地址的低四位
301         write_command(0x10);     // 设置列地址的高四位
302         write_data_page(OLED_GRAM[i], OLED_PAGE_SIZES);
303     }
304 #endif
305 #if RECORD_SCREEN == 1
306     uint16_t zip_len = 0;
307     zip_oled_gram(oled_remote_buffer, &zip_len);
308 
309     gettimeofday(&tv, NULL);
310 
311     if (zip_len <= 8 * 132) {
312         // 压缩有效
313         printf("pyszip|%d%d.", tv.tv_sec, tv.tv_usec / 1000);
314         printf("%03ld|", tv.tv_usec / 1000);
315         uint16_t cnt = 0;
316         for (int i = 0; i < zip_len; i++) {
317             printf("%02X", oled_remote_buffer[i]);
318             cnt += (i % 2 ? oled_remote_buffer[i] : 0);
319         }
320         printf("|%d\n", cnt);
321     } else {
322         // 压缩无效
323         printf("pysorg|%d%d.", tv.tv_sec, tv.tv_usec / 1000);
324         printf("%03ld|", tv.tv_usec / 1000);
325         for (int i = 0; i < 8; i++) {
326             for (int j = 0; j < 132; j++) {
327                 printf("%02X", OLED_GRAM[i][j]);
328             }
329         }
330         printf("|1056\n");
331     }
332 #endif
333 }
334 
OLED_Clear(void)335 void OLED_Clear(void)
336 {
337     uint8_t i, j;
338     for (i = 0; i < 8; i++)
339         for (j = 0; j < OLED_PAGE_SIZES; j++)
340             OLED_GRAM[i][j] = 0x0;
341 }
342 
OLED_Full(void)343 void OLED_Full(void)
344 {
345     uint8_t i, j;
346     for (i = 0; i < 8; i++)
347         for (j = 0; j < OLED_PAGE_SIZES; j++)
348             OLED_GRAM[i][j] = 0xff;
349 }
350 
OLED_Frame_Draw(uint8_t frame[][132])351 void OLED_Frame_Draw(uint8_t frame[][132])
352 {
353     uint8_t i, j;
354     for (i = 0; i < 8; i++) {
355         for (j = 0; j < OLED_PAGE_SIZES; j++) {
356             OLED_GRAM[i][j] = frame[i][j];
357         }
358         printf("OLED_GRAM[%d][0] = %02X;\n", i, OLED_GRAM[i][0]);
359     }
360 }
361 
362 // OLED_Icon_Draw(-10, -10, icon_t *icon, 0)
363 // 0 完全不覆盖
364 // 1 完全覆盖
365 // 2 mask覆盖
OLED_Icon_Draw(int16_t x,int16_t y,icon_t * icon,uint8_t mode)366 void OLED_Icon_Draw(int16_t x, int16_t y, icon_t *icon, uint8_t mode)
367 {
368     int16_t width_byte  = icon->width;
369     int16_t height_byte = icon->height / 8 + (icon->height % 8 != 0);
370     int16_t column_0    = x;
371     int16_t page_0      = (y < 0) ? (y / 8 - (y % 8 != 0)) : (y / 8);
372     int8_t  bit_offset  = (y % 8 < 0) ? (y % 8 + 8) : (y % 8);
373     if (mode == 2 && icon->p_icon_mask == NULL) {
374         mode = 0;
375     }
376     for (int byte_y = 0; (byte_y < height_byte) && (byte_y + page_0 < 8);
377             byte_y++) {
378         if (page_0 + byte_y + 1 < 0)
379             continue;
380         for (int byte_x = 0; (byte_x < width_byte) && (byte_x + column_0 < 132);
381                 byte_x++) {
382             if (byte_x + column_0 < 0)
383                 continue;
384             // 绘画处在当前 page 的部分
385             if (page_0 + byte_y >= 0) {
386                 if (mode == 1) {
387                     OLED_GRAM[page_0 + byte_y][column_0 + byte_x] &=
388                         ~(0xff << bit_offset);
389                 }
390                 if (mode == 2) {
391                     OLED_GRAM[page_0 + byte_y][column_0 + byte_x] &=
392                         ~((icon->p_icon_mask[byte_y * width_byte + byte_x])
393                           << bit_offset);
394                 }
395                 OLED_GRAM[page_0 + byte_y][column_0 + byte_x] |=
396                     (icon->p_icon_data[byte_y * width_byte + byte_x])
397                     << bit_offset;
398             }
399             // 绘画处在下一个 page 的部分
400             if (bit_offset > 0 && page_0 + byte_y + 1 >= 0 &&
401                     page_0 + byte_y + 1 < 8) {
402                 if (mode == 1) {
403                     OLED_GRAM[page_0 + byte_y + 1][column_0 + byte_x] &=
404                         ~(0xff >> (8 - bit_offset));
405                 }
406                 if (mode == 2) {
407                     OLED_GRAM[page_0 + byte_y + 1][column_0 + byte_x] &=
408                         ~((icon->p_icon_mask[byte_y * width_byte + byte_x]) >>
409                           (8 - bit_offset));
410                 }
411                 OLED_GRAM[page_0 + byte_y + 1][column_0 + byte_x] |=
412                     (icon->p_icon_data[byte_y * width_byte + byte_x]) >>
413                     (8 - bit_offset);
414             }
415         }
416     }
417 }
418 
419 /* 画点函数,以屏幕像素点为单位,以左上角为原点 x:0~127 y:0~63
420 (x,y)坐标换算:OLED_GRAM[x][7-y/8]|=1<<(7-y%8);
421 mode取1正显,取0反显
422 */
OLED_DrawPoint(int16_t x,int16_t y,uint8_t mode)423 void OLED_DrawPoint(int16_t x, int16_t y, uint8_t mode)
424 {
425     if ((x > (131)) || (y > 63) || x < 0 || y < 0)
426         return;
427 
428     uint8_t page       = y / 8;
429     uint8_t bit_offset = y % 8;
430     uint8_t mask       = 0x01 << bit_offset;
431 
432     if (mode == 0)
433         OLED_GRAM[page][x] &= ~mask;
434     if (mode == 1)
435         OLED_GRAM[page][x] |= mask;
436     if (mode == 2)
437         OLED_GRAM[page][x] ^= mask;
438 }
439 
440 /* 在(x,y)坐标正显/反显指定大小字符chr
441 mode:0是反显,1是正常显示
442 size:12/16/24
443 ASCII字符集:
444 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOP
445 QRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
446 */
OLED_Show_Char(uint8_t x,uint8_t y,uint8_t chr,uint8_t size,uint8_t mode)447 void OLED_Show_Char(uint8_t x,
448                     uint8_t y,
449                     uint8_t chr,
450                     uint8_t size,
451                     uint8_t mode)
452 {
453     /* temp是当前对应的一个字节的点集,y0是初始坐标 */
454     uint8_t temp, t, t1;
455     uint8_t y0 = y;
456     /* csize是单个字符所占字节的多少 */
457     uint8_t csize = (size / 8 + ((size % 8) ? 1 : 0)) * (size / 2);
458     /* 求出偏移的地址差,即得到该字符在字库中的序号(从零开始) */
459     /* chr会锁定字符在字库中的的序号 */
460     // LOGI("APP", "++++ char=%c size=%d\n", chr, csize);
461     chr = chr - ' ';
462     /* 相应字符点集有多少个字节 */
463     for (t = 0; t < csize; t++) {
464         /* 根据字符的大小选择相应字库,根据chr得到具体的字符地址 */
465         switch (size) {
466             case 12:
467                 temp = sh1106_asc2_1206[chr][t];
468                 break; // 12x6(行x列)
469             case 16:
470                 temp = sh1106_asc2_1608[chr][t];
471                 break; // 16x8
472             case 24:
473                 temp = sh1106_asc2_2412[chr][t];
474                 break; // 24x12
475             default :
476                 return; // 没有相应字库
477         }
478         // LOGI("APP", " new char x= %d,y=%d,t =%d %d\n", x, y, t, temp);
479         /* 画出每一列的点 */
480         for (t1 = 0; t1 < 8; t1++) {
481             if (temp & 0x80)
482                 OLED_DrawPoint(x, y, mode);
483             else
484                 OLED_DrawPoint(x, y, !mode);
485 
486             temp <<= 1;
487             y++;
488             // LOGI("APP", "x= %d,y=%d\n",x,y);
489             /* 根据给出每一列的像素点的多少,判断列是否满:
490             满了就换列,不满继续在此列画点 (与字库画点原理相关)
491             */
492             if ((y - y0) == size) {
493                 // LOGI("APP", "new line\n");
494                 y = y0;
495                 x++;
496                 /* 一列满,跳出循环,直接转到下一个字节点集的打印 */
497                 break;
498             }
499         }
500     }
501 }
502 /* (x,y)是显示的坐标,*p是字符串的首地址,size是字符点集大小 */
OLED_Show_String(uint8_t x,uint8_t y,const uint8_t * p,uint8_t size,uint8_t mode)503 void OLED_Show_String(uint8_t        x,
504                       uint8_t        y,
505                       const uint8_t *p,
506                       uint8_t        size,
507                       uint8_t        mode)
508 {
509     /* 判断是否合法字符,同时也限定了范围 */
510     while ((*p <= '~') && (*p >= ' ')) {
511         /* 如果初始行放不下,移动到下一行 */
512         if (x > (OLED_PAGE_SIZES - (size / 2))) {
513             x = 0;
514             y = y + size;
515         }
516         if (y > (64 - size)) {
517             x = y = 0;
518             OLED_Clear();
519         }
520 
521         OLED_Show_Char(x, y, *p, size, mode);
522         /* 移动到下一个字符位置,size/2是因为做点集时就是:行X列,而且
523          * 行=2X列,所以size就是行数 */
524         x = x + size / 2;
525         p++;
526     }
527     // OLED_Refresh_GRAM();
528 }
529 // end native
530 
command_list(void)531 static void command_list(void)
532 {
533     /* 开始写入初始化命令 */
534     write_command(0xAE); // 关闭显示
535     write_command(0xD5); // 设置时钟分频因子
536     write_command(80);
537 
538     write_command(0xA8); // 设置驱动路数
539     write_command(0x3F); // 路数默认0x3F(1/64)
540 
541     write_command(0xD3); // 设置显示偏移
542     write_command(0x00); // 偏移默认为0
543 
544     write_command(0x40); // 设置显示开始行[5:0]
545 
546     write_command(0x8D); // 电荷泵设置
547     write_command(0x14); // bit2,开启/关闭
548 
549     write_command(0x20); // 设置内存地址模式
550     write_command(0x02); // [1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
551 
552     write_command(0xA1); // 段重定义设置,bit0:0,0->0;1,0->127;
553     write_command(0xC8); // 设置COM扫描方向;bit3:0,普通模式;1,重定义模式
554     // COM[N-1]->COM0;N:驱动路数
555     write_command(0xDA); // 设置COM硬件引脚配置
556     write_command(0x12); // [5:4]配置
557 
558     write_command(0x81); // 对比度设置
559     write_command(0xEF); // 默认0x7F(范围1~255,越大越亮)
560 
561     write_command(0xD9); // 设置预充电周期
562     write_command(0xF1); // [3:0],PHASE 1;[7:4],PHASE 2;
563 
564     write_command(0xDB); // 设置VCOMH 电压倍率
565     write_command(0x30); // [6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;
566 
567     write_command(0xA4); // 全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
568     write_command(0xA6); // 设置显示方式;bit0:1,反相显示;0,正常显示
569 
570     write_command(0xAF); // 开启显示
571 
572     OLED_Clear();
573     OLED_Refresh_GRAM();
574     aos_msleep(500);
575 }
576 
OLED_DrawLine(int16_t x1,int16_t y1,int16_t x2,int16_t y2,uint8_t mode)577 void OLED_DrawLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t mode)
578 {
579     uint16_t t;
580     int      xerr = 1, yerr = 1, delta_x, delta_y, distance;
581     int      incx, incy, uRow, uCol;
582 
583     delta_x = x2 - x1;
584     delta_y = y2 - y1;
585 
586     uRow = x1;
587     uCol = y1;
588     if (delta_x > 0) {
589         incx = 1;
590     } else if (delta_x == 0) {
591         incx = 0;
592     } else {
593         incx    = -1;
594         delta_x = -delta_x;
595     }
596 
597     if (delta_y > 0) {
598         incy = 1;
599     } else if (delta_y == 0) {
600         incy = 0;
601     } else {
602         incy    = -1;
603         delta_y = -delta_y;
604     }
605 
606     if (delta_x > delta_y)
607         distance = delta_x;
608     else
609         distance = delta_y;
610 
611     for (t = 0; t <= distance; t++) {
612         OLED_DrawPoint(uRow, uCol, mode);
613         xerr += delta_x;
614         yerr += delta_y;
615 
616         if (xerr > distance / 2) {
617             xerr -= distance;
618             uRow += incx;
619         }
620         if (yerr > distance) {
621             yerr -= distance;
622             uCol += incy;
623         }
624     }
625 }
626 
OLED_DrawLine_ByAngle(int16_t x0,int16_t y0,int16_t angle,int16_t length,uint8_t mode)627 void OLED_DrawLine_ByAngle(int16_t x0,
628                            int16_t y0,
629                            int16_t angle,
630                            int16_t length,
631                            uint8_t mode)
632 {
633     int16_t x1 = x0 + length * cos(angle * PI / 180.0);
634     int16_t y1 = y0 + length * sin(angle * PI / 180.0);
635     OLED_DrawLine(x0, y0, x1, y1, mode);
636 }
637 
OLED_DrawHorizontalLine(uint8_t x,uint8_t y,uint8_t length,uint8_t mode)638 void OLED_DrawHorizontalLine(uint8_t x, uint8_t y, uint8_t length, uint8_t mode)
639 {
640     if (y < 0 || y >= 64) {
641         return;
642     }
643 
644     if (x < 0) {
645         length += x;
646         x = 0;
647     }
648 
649     if ((x + length) > 132) {
650         length = (132 - x);
651     }
652 
653     if (length <= 0) {
654         return;
655     }
656 
657     while (length--) {
658         OLED_DrawPoint(x + length, y, mode);
659     }
660 }
661 
OLED_DrawVerticalLine(uint8_t x,uint8_t y,uint8_t length,uint8_t mode)662 void OLED_DrawVerticalLine(uint8_t x, uint8_t y, uint8_t length, uint8_t mode)
663 {
664     if (x < 0 || x >= 132) {
665         return;
666     }
667 
668     if (x < 0) {
669         length += x;
670         x = 0;
671     }
672 
673     if ((y + length) > 64) {
674         length = (64 - x);
675     }
676 
677     if (length <= 0) {
678         return;
679     }
680 
681     while (length--) {
682         OLED_DrawPoint(x, y + length, mode);
683     }
684 }
685 
OLED_DrawRect(uint8_t x,uint8_t y,uint8_t width,uint8_t height,uint8_t mode)686 void OLED_DrawRect(uint8_t x,
687                    uint8_t y,
688                    uint8_t width,
689                    uint8_t height,
690                    uint8_t mode)
691 {
692     OLED_DrawHorizontalLine(x, y, width, mode);
693     OLED_DrawVerticalLine(x, y, height, mode);
694     OLED_DrawVerticalLine(x + width - 1, y, height, mode);
695     OLED_DrawHorizontalLine(x, y + height - 1, width, mode);
696 }
697 
OLED_FillRect(uint8_t xMove,uint8_t yMove,uint8_t width,uint8_t height,uint8_t mode)698 void OLED_FillRect(uint8_t xMove,
699                    uint8_t yMove,
700                    uint8_t width,
701                    uint8_t height,
702                    uint8_t mode)
703 {
704     for (uint8_t x = xMove; x < xMove + width; x++) {
705         OLED_DrawVerticalLine(x, yMove, height, mode);
706     }
707 }
708 
OLED_DrawCircle(uint8_t x0,uint8_t y0,uint8_t radius,uint8_t width,uint8_t mode)709 void OLED_DrawCircle(uint8_t x0,
710                      uint8_t y0,
711                      uint8_t radius,
712                      uint8_t width,
713                      uint8_t mode)
714 {
715     OLED_FillCircle(x0, y0, radius, mode);
716     OLED_FillCircle(x0, y0, radius - width, !mode);
717 }
718 
OLED_FillCircle(uint8_t x0,uint8_t y0,uint8_t r,uint8_t mode)719 void OLED_FillCircle(uint8_t x0, uint8_t y0, uint8_t r, uint8_t mode)
720 {
721     int x, y;
722     int deltax, deltay;
723     int d;
724     int xi;
725     x = 0;
726     y = r;
727     deltax = 3;
728     deltay = 2 - r - r;
729     d = 1 - r;
730 
731     OLED_DrawPoint(x + x0, y + y0, mode);
732     OLED_DrawPoint(x + x0, -y + y0, mode);
733     for (xi = -r + x0; xi <= r + x0; xi++)
734         OLED_DrawPoint(xi, y0, mode);
735     while (x < y) {
736         if (d < 0) {
737             d += deltax;
738             deltax += 2;
739             x++;
740         } else {
741             d += (deltax + deltay);
742             deltax += 2;
743             deltay += 2;
744             x++;
745             y--;
746         }
747         for (xi = -x + x0; xi <= x + x0; xi++) {
748             OLED_DrawPoint(xi, -y + y0, mode);
749             OLED_DrawPoint(xi, y + y0, mode);
750         }
751         for (xi = -y + x0; xi <= y + x0; xi++) {
752             OLED_DrawPoint(xi, -x + y0, mode);
753             OLED_DrawPoint(xi, x + y0, mode);
754         }
755     }
756 }
757 
hardware_init(void)758 static uint8_t hardware_init(void)
759 {
760     uint8_t ret = 0;
761 
762     ret |= OLED_SPI_Init();
763 
764     ret |= OLED_GPIO_Init();
765 
766     if (ret) {
767         printf("hardware_init fail\r\n");
768         return ret;
769     }
770     return ret;
771 }
772 
773 /* (x,y)是显示的坐标,*p是字符串的首地址,size是字符点集大小 */
sh1106_show_string(uint8_t x,uint8_t y,const uint8_t * p,uint8_t size,uint8_t mode)774 void sh1106_show_string(uint8_t        x,
775                         uint8_t        y,
776                         const uint8_t *p,
777                         uint8_t        size,
778                         uint8_t        mode)
779 {
780     /* 判断是否合法字符,同时也限定了范围 */
781     while ((*p <= '~') && (*p >= ' ')) {
782         /* 如果初始行放不下,移动到下一行 */
783         if (x > (OLED_PAGE_SIZES - (size / 2))) {
784             x = 0;
785             y = y + size;
786         }
787         if (y > (64 - size)) {
788             x = y = 0;
789             OLED_Clear();
790         }
791 
792         OLED_Show_Char(x, y, *p, size, mode);
793         /* 移动到下一个字符位置,size/2是因为做点集时就是:行X列,而且
794          * 行=2X列,所以size就是行数 */
795         x = x + size / 2;
796         p++;
797     }
798     OLED_Refresh_GRAM();
799 }
800 
sh1106_init(void)801 uint8_t sh1106_init(void)
802 {
803     uint8_t err_code;
804 
805     err_code = hardware_init();
806     if (err_code != 0) {
807         return err_code;
808     }
809     command_list();
810     return err_code;
811 }
812