From 6bfb55d1f47069e1ccdf0aa29088636909818081 Mon Sep 17 00:00:00 2001 From: zhaohe Date: Mon, 22 Jan 2024 22:35:12 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=8D=95=E5=AF=BC=E5=BA=95?= =?UTF-8?q?=E5=B1=82=E9=A9=B1=E5=8A=A8=E7=A8=8B=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 6 +- README.md | 7 + app/app.uvoptx | 182 +- app/app.uvprojx | 30 + app/src/basic/m24m02/m24m02.c | 0 app/src/basic/m24m02/m24m02.h | 0 app/src/basic/ssd1306/driver_ssd1306.c | 2356 ++++++++++++++++++++++ app/src/basic/ssd1306/driver_ssd1306.h | 1105 ++++++++++ app/src/basic/ssd1306/driver_ssd1306_basic.c | 577 ++++++ app/src/basic/ssd1306/driver_ssd1306_basic.h | 203 ++ app/src/basic/ssd1306/driver_ssd1306_font.h | 350 ++++ app/src/basic/ssd1306/driver_ssd1306_interface.c | 68 + app/src/basic/ssd1306/driver_ssd1306_interface.h | 192 ++ app/src/one_conduction/one_conduction_board.c | 280 +++ app/src/one_conduction/one_conduction_board.h | 67 +- m24m02-dr.pdf | Bin 0 -> 1024914 bytes 16 files changed, 5346 insertions(+), 77 deletions(-) create mode 100644 app/src/basic/m24m02/m24m02.c create mode 100644 app/src/basic/m24m02/m24m02.h create mode 100644 app/src/basic/ssd1306/driver_ssd1306.c create mode 100644 app/src/basic/ssd1306/driver_ssd1306.h create mode 100644 app/src/basic/ssd1306/driver_ssd1306_basic.c create mode 100644 app/src/basic/ssd1306/driver_ssd1306_basic.h create mode 100644 app/src/basic/ssd1306/driver_ssd1306_font.h create mode 100644 app/src/basic/ssd1306/driver_ssd1306_interface.c create mode 100644 app/src/basic/ssd1306/driver_ssd1306_interface.h create mode 100644 m24m02-dr.pdf diff --git a/.vscode/settings.json b/.vscode/settings.json index a1e24f1..9285178 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -52,6 +52,10 @@ "diskio_blkdev.h": "c", "three_conduction_main.h": "c", "one_conduction_main.h": "c", - "one_conduction_board.h": "c" + "one_conduction_board.h": "c", + "driver_ssd1306.h": "c", + "driver_ssd1306_font.h": "c", + "driver_ssd1306_basic.h": "c", + "driver_ssd1306_interface.h": "c" } } \ No newline at end of file diff --git a/README.md b/README.md index 8bca8f0..efc73b0 100644 --- a/README.md +++ b/README.md @@ -65,4 +65,11 @@ PIN4 PIN30/PIN31 PIN28/PIN29 PIN11/PIN20 +``` + +``` +屏幕驱动: +https://github.com/libdriver/ssd1306 +1306驱动和1312是一样的,只不过1312默认是镜像的 + ``` \ No newline at end of file diff --git a/app/app.uvoptx b/app/app.uvoptx index 72e05c0..62ad6a9 100644 --- a/app/app.uvoptx +++ b/app/app.uvoptx @@ -488,6 +488,42 @@ 0 0 + + 1 + 7 + 1 + 0 + 0 + 0 + .\src\basic\ssd1306\driver_ssd1306.c + driver_ssd1306.c + 0 + 0 + + + 1 + 8 + 1 + 0 + 0 + 0 + .\src\basic\ssd1306\driver_ssd1306_basic.c + driver_ssd1306_basic.c + 0 + 0 + + + 1 + 9 + 1 + 0 + 0 + 0 + .\src\basic\ssd1306\driver_ssd1306_interface.c + driver_ssd1306_interface.c + 0 + 0 + @@ -498,7 +534,7 @@ 0 2 - 7 + 10 1 0 0 @@ -518,7 +554,7 @@ 0 3 - 8 + 11 1 0 0 @@ -530,7 +566,7 @@ 3 - 9 + 12 1 0 0 @@ -550,7 +586,7 @@ 0 4 - 10 + 13 1 0 0 @@ -570,7 +606,7 @@ 0 5 - 11 + 14 1 0 0 @@ -582,7 +618,7 @@ 5 - 12 + 15 1 0 0 @@ -594,7 +630,7 @@ 5 - 13 + 16 1 0 0 @@ -606,7 +642,7 @@ 5 - 14 + 17 1 0 0 @@ -618,7 +654,7 @@ 5 - 15 + 18 1 0 0 @@ -630,7 +666,7 @@ 5 - 16 + 19 1 0 0 @@ -642,7 +678,7 @@ 5 - 17 + 20 1 0 0 @@ -654,7 +690,7 @@ 5 - 18 + 21 1 0 0 @@ -674,7 +710,7 @@ 0 6 - 19 + 22 1 0 0 @@ -694,7 +730,7 @@ 0 7 - 20 + 23 1 0 0 @@ -706,7 +742,7 @@ 7 - 21 + 24 1 0 0 @@ -718,7 +754,7 @@ 7 - 22 + 25 1 0 0 @@ -730,7 +766,7 @@ 7 - 23 + 26 1 0 0 @@ -742,7 +778,7 @@ 7 - 24 + 27 1 0 0 @@ -754,7 +790,7 @@ 7 - 25 + 28 1 0 0 @@ -766,7 +802,7 @@ 7 - 26 + 29 1 0 0 @@ -778,7 +814,7 @@ 7 - 27 + 30 1 0 0 @@ -790,7 +826,7 @@ 7 - 28 + 31 1 0 0 @@ -802,7 +838,7 @@ 7 - 29 + 32 1 0 0 @@ -814,7 +850,7 @@ 7 - 30 + 33 1 0 0 @@ -826,7 +862,7 @@ 7 - 31 + 34 1 0 0 @@ -838,7 +874,7 @@ 7 - 32 + 35 1 0 0 @@ -850,7 +886,7 @@ 7 - 33 + 36 1 0 0 @@ -862,7 +898,7 @@ 7 - 34 + 37 1 0 0 @@ -874,7 +910,7 @@ 7 - 35 + 38 1 0 0 @@ -886,7 +922,7 @@ 7 - 36 + 39 1 0 0 @@ -898,7 +934,7 @@ 7 - 37 + 40 1 0 0 @@ -918,7 +954,7 @@ 0 8 - 38 + 41 1 0 0 @@ -930,7 +966,7 @@ 8 - 39 + 42 1 0 0 @@ -942,7 +978,7 @@ 8 - 40 + 43 1 0 0 @@ -954,7 +990,7 @@ 8 - 41 + 44 1 0 0 @@ -966,7 +1002,7 @@ 8 - 42 + 45 1 0 0 @@ -978,7 +1014,7 @@ 8 - 43 + 46 1 0 0 @@ -990,7 +1026,7 @@ 8 - 44 + 47 1 0 0 @@ -1002,7 +1038,7 @@ 8 - 45 + 48 1 0 0 @@ -1014,7 +1050,7 @@ 8 - 46 + 49 1 0 0 @@ -1026,7 +1062,7 @@ 8 - 47 + 50 1 0 0 @@ -1038,7 +1074,7 @@ 8 - 48 + 51 1 0 0 @@ -1050,7 +1086,7 @@ 8 - 49 + 52 1 0 0 @@ -1062,7 +1098,7 @@ 8 - 50 + 53 1 0 0 @@ -1074,7 +1110,7 @@ 8 - 51 + 54 1 0 0 @@ -1086,7 +1122,7 @@ 8 - 52 + 55 1 0 0 @@ -1098,7 +1134,7 @@ 8 - 53 + 56 1 0 0 @@ -1110,7 +1146,7 @@ 8 - 54 + 57 1 0 0 @@ -1122,7 +1158,7 @@ 8 - 55 + 58 1 0 0 @@ -1134,7 +1170,7 @@ 8 - 56 + 59 1 0 0 @@ -1146,7 +1182,7 @@ 8 - 57 + 60 1 0 0 @@ -1158,7 +1194,7 @@ 8 - 58 + 61 1 0 0 @@ -1170,7 +1206,7 @@ 8 - 59 + 62 1 0 0 @@ -1182,7 +1218,7 @@ 8 - 60 + 63 1 0 0 @@ -1194,7 +1230,7 @@ 8 - 61 + 64 1 0 0 @@ -1206,7 +1242,7 @@ 8 - 62 + 65 1 0 0 @@ -1218,7 +1254,7 @@ 8 - 63 + 66 1 0 0 @@ -1230,7 +1266,7 @@ 8 - 64 + 67 1 0 0 @@ -1250,7 +1286,7 @@ 0 9 - 65 + 68 1 0 0 @@ -1262,7 +1298,7 @@ 9 - 66 + 69 1 0 0 @@ -1274,7 +1310,7 @@ 9 - 67 + 70 1 0 0 @@ -1286,7 +1322,7 @@ 9 - 68 + 71 1 0 0 @@ -1298,7 +1334,7 @@ 9 - 69 + 72 1 0 0 @@ -1310,7 +1346,7 @@ 9 - 70 + 73 1 0 0 @@ -1330,7 +1366,7 @@ 0 10 - 71 + 74 1 0 0 @@ -1342,7 +1378,7 @@ 10 - 72 + 75 1 0 0 @@ -1354,7 +1390,7 @@ 10 - 73 + 76 1 0 0 @@ -1374,7 +1410,7 @@ 0 11 - 74 + 77 1 0 0 @@ -1386,7 +1422,7 @@ 11 - 75 + 78 1 0 0 @@ -1398,7 +1434,7 @@ 11 - 76 + 79 1 0 0 @@ -1418,7 +1454,7 @@ 0 12 - 77 + 80 1 0 0 @@ -1438,7 +1474,7 @@ 0 13 - 78 + 81 1 0 0 @@ -1450,7 +1486,7 @@ 13 - 79 + 82 1 0 0 diff --git a/app/app.uvprojx b/app/app.uvprojx index 98703d6..001de2e 100644 --- a/app/app.uvprojx +++ b/app/app.uvprojx @@ -413,6 +413,21 @@ 1 .\src\one_conduction\one_conduction_main.c + + driver_ssd1306.c + 1 + .\src\basic\ssd1306\driver_ssd1306.c + + + driver_ssd1306_basic.c + 1 + .\src\basic\ssd1306\driver_ssd1306_basic.c + + + driver_ssd1306_interface.c + 1 + .\src\basic\ssd1306\driver_ssd1306_interface.c + @@ -4162,6 +4177,21 @@ 1 .\src\one_conduction\one_conduction_main.c + + driver_ssd1306.c + 1 + .\src\basic\ssd1306\driver_ssd1306.c + + + driver_ssd1306_basic.c + 1 + .\src\basic\ssd1306\driver_ssd1306_basic.c + + + driver_ssd1306_interface.c + 1 + .\src\basic\ssd1306\driver_ssd1306_interface.c + diff --git a/app/src/basic/m24m02/m24m02.c b/app/src/basic/m24m02/m24m02.c new file mode 100644 index 0000000..e69de29 diff --git a/app/src/basic/m24m02/m24m02.h b/app/src/basic/m24m02/m24m02.h new file mode 100644 index 0000000..e69de29 diff --git a/app/src/basic/ssd1306/driver_ssd1306.c b/app/src/basic/ssd1306/driver_ssd1306.c new file mode 100644 index 0000000..ba864fc --- /dev/null +++ b/app/src/basic/ssd1306/driver_ssd1306.c @@ -0,0 +1,2356 @@ +/** + * Copyright (c) 2015 - present LibDriver All rights reserved + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * @file driver_ssd1306.c + * @brief driver ssd1306 source file + * @version 2.0.0 + * @author Shifeng Li + * @date 2021-03-30 + * + *

history

+ * + *
Date Version Author Description + *
2021/03/30 2.0 Shifeng Li format the code + *
2020/12/10 1.0 Shifeng Li first upload + *
+ */ + +#include "driver_ssd1306.h" +#include "driver_ssd1306_font.h" + +/** + * @brief chip information definition + */ +#define CHIP_NAME "Solomon Systech SSD1306" /**< chip name */ +#define MANUFACTURER_NAME "Solomon Systech" /**< manufacturer name */ +#define SUPPLY_VOLTAGE_MIN 1.65f /**< chip min supply voltage */ +#define SUPPLY_VOLTAGE_MAX 3.3f /**< chip max supply voltage */ +#define MAX_CURRENT 0.78f /**< chip max current */ +#define TEMPERATURE_MIN -40.0f /**< chip min operating temperature */ +#define TEMPERATURE_MAX 85.0f /**< chip max operating temperature */ +#define DRIVER_VERSION 2000 /**< driver version */ + +/** + * @brief chip command data definition + */ +#define SSD1306_CMD 0 /**< command */ +#define SSD1306_DATA 1 /**< data */ + +/** + * @brief chip command definition + */ +#define SSD1306_CMD_LOWER_COLUMN_START_ADDRESS 0x00 /**< command lower column start address */ +#define SSD1306_CMD_HIGHER_COLUMN_START_ADDRESS 0x10 /**< command higher column start address */ +#define SSD1306_CMD_MEMORY_ADDRESSING_MODE 0x20 /**< command memory addressing mode */ +#define SSD1306_CMD_SET_COLUMN_ADDRESS 0x21 /**< command set column address */ +#define SSD1306_CMD_SET_PAGE_ADDRESS 0x22 /**< command set page address */ +#define SSD1306_CMD_SET_FADE_OUT_AND_BLINKING 0x23 /**< command set fade out and blinking */ +#define SSD1306_CMD_RIGHT_HORIZONTAL_SCROLL 0x26 /**< command right horizontal scroll */ +#define SSD1306_CMD_LEFT_HORIZONTAL_SCROLL 0x27 /**< command left horizontal scroll */ +#define SSD1306_CMD_VERTICAL_RIGHT_HORIZONTAL_SCROLL 0x29 /**< command vertical right horizontal scroll */ +#define SSD1306_CMD_VERTICAL_LEFT_HORIZONTAL_SCROLL 0x2A /**< command vertical left horizontal scroll */ +#define SSD1306_CMD_DEACTIVATE_SCROLL 0x2E /**< command deactivate scroll */ +#define SSD1306_CMD_ACTIVATE_SCROLL 0x2F /**< command activate scroll */ +#define SSD1306_CMD_DISPLAY_START_LINE 0x40 /**< command display start line */ +#define SSD1306_CMD_CONTRAST_CONTROL 0x81 /**< command contrast control */ +#define SSD1306_CMD_CHARGE_PUMP_SETTING 0x8D /**< command charge pump setting */ +#define SSD1306_CMD_COLUMN_0_MAPPED_TO_SEG0 0xA0 /**< command column 0 mapped to seg 0 */ +#define SSD1306_CMD_COLUMN_127_MAPPED_TO_SEG0 0xA1 /**< command column 127 mapped to seg 0 */ +#define SSD1306_CMD_VERTICAL_SCROLL_AREA 0xA3 /**< command vertical scroll area */ +#define SSD1306_CMD_ENTIRE_DISPLAY_OFF 0xA4 /**< command entire display off */ +#define SSD1306_CMD_ENTIRE_DISPLAY_ON 0xA5 /**< command entire display on */ +#define SSD1306_CMD_NORMAL_DISPLAY 0xA6 /**< command normal display */ +#define SSD1306_CMD_INVERSE_DISPLAY 0xA7 /**< command inverse display */ +#define SSD1306_CMD_MULTIPLEX_RATIO 0xA8 /**< command multiplex ratio */ +#define SSD1306_CMD_DISPLAY_OFF 0xAE /**< command display off */ +#define SSD1306_CMD_DISPLAY_ON 0xAF /**< command display on */ +#define SSD1306_CMD_PAGE_ADDR 0xB0 /**< command page address */ +#define SSD1306_CMD_SCAN_DIRECTION_COM0_START 0xC0 /**< command scan direction com 0 start */ +#define SSD1306_CMD_SCAN_DIRECTION_COMN_1_START 0xC8 /**< command scan direction com n-1 start */ +#define SSD1306_CMD_DISPLAY_OFFSET 0xD3 /**< command display offset */ +#define SSD1306_CMD_DISPLAY_CLOCK_DIVIDE 0xD5 /**< command display clock divide */ +#define SSD1306_CMD_SET_ZOOM_IN 0xD6 /**< command set zoom in */ +#define SSD1306_CMD_PRE_CHARGE_PERIOD 0xD9 /**< command pre charge period */ +#define SSD1306_CMD_COM_PINS_CONF 0xDA /**< command com pins conf */ +#define SSD1306_CMD_COMH_DESLECT_LEVEL 0xDB /**< command comh deslect level */ +#define SSD1306_CMD_NOP 0xE3 /**< command nop */ + +/** + * @brief write one byte + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] data is the write data + * @param[in] cmd is the command or data type + * @return status code + * - 0 success + * - 1 write failed + * @note none + */ +static uint8_t a_ssd1306_write_byte(ssd1306_handle_t *handle, uint8_t data, uint8_t cmd) +{ + uint8_t res; + + if (handle->iic_spi == SSD1306_INTERFACE_IIC) /* if iic */ + { + if (cmd != 0) /* if data */ + { + if (handle->iic_write(handle->iic_addr, 0x40, &data, 1) != 0) /* write data */ + { + return 1; /* return error */ + } + else + { + return 0; /* success return 0 */ + } + } + else + { + if (handle->iic_write(handle->iic_addr, 0x00, &data, 1) != 0) /* write command */ + { + return 1; /* return error */ + } + else + { + return 0; /* success return 0 */ + } + } + } + else if (handle->iic_spi == SSD1306_INTERFACE_SPI) /* if spi */ + { + res = handle->spi_cmd_data_gpio_write(cmd); /* write data command */ + if (res != 0) /* check error */ + { + return 1; /* return error */ + } + + if (handle->spi_write_cmd(&data, 1) != 0) /* write command */ + { + return 1; /* return error */ + } + else + { + return 0; /* success return 0 */ + } + } + else + { + return 1; /* return error */ + } +} + +/** + * @brief write multiple bytes + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] *data points to a data buffer + * @param[in] len is the data length + * @param[in] cmd is the command or data type + * @return status code + * - 0 success + * - 1 write failed + * @note none + */ +static uint8_t a_ssd1306_multiple_write_byte(ssd1306_handle_t *handle, uint8_t *data, uint8_t len, uint8_t cmd) +{ + uint8_t res; + + if (handle->iic_spi == SSD1306_INTERFACE_IIC) /* if iic */ + { + if (cmd != 0) /* if data */ + { + if (handle->iic_write(handle->iic_addr, 0x40, data, len) != 0) /* write data */ + { + return 1; /* return error */ + } + else + { + return 0; /* success return 0 */ + } + } + else + { + if (handle->iic_write(handle->iic_addr, 0x00, data, len) != 0) /* write command */ + { + return 1; /* return error */ + } + else + { + return 0; /* success return 0 */ + } + } + } + else if (handle->iic_spi == SSD1306_INTERFACE_SPI) /* if spi */ + { + res = handle->spi_cmd_data_gpio_write(cmd); /* write data command */ + if (res != 0) /* check error */ + { + return 1; /* return error */ + } + + if (handle->spi_write_cmd(data, len) != 0) /* write command */ + { + return 1; /* return error */ + } + else + { + return 0; /* success return 0 */ + } + } + else + { + return 1; /* return error */ + } +} + +/** + * @brief draw a point in gram + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] x is the coordinate x + * @param[in] y is the coordinate y + * @param[in] data is the write data + * @return status code + * - 0 success + * - 1 gram draw point failed + * @note none + */ +static uint8_t a_ssd1306_gram_draw_point(ssd1306_handle_t *handle, uint8_t x, uint8_t y, uint8_t data) +{ + uint8_t pos; + uint8_t bx; + uint8_t temp = 0; + + pos = y / 8; /* get y page */ + bx = y % 8; /* get y point */ + temp = 1 << bx; /* set data */ + if (data != 0) /* if 1 */ + { + handle->gram[x][pos] |= temp; /* set 1 */ + } + else + { + handle->gram[x][pos] &= ~temp; /* set 0 */ + } + + return 0; /* success return 0 */ +} + +/** + * @brief draw a char in gram + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] x is the coordinate x + * @param[in] y is the coordinate y + * @param[in] chr is the write char + * @param[in] size is the char size + * @param[in] mode is the display mode + * @return status code + * - 0 success + * - 1 gram show char failed + * @note none + */ +static uint8_t a_ssd1306_gram_show_char(ssd1306_handle_t *handle, uint8_t x, uint8_t y, uint8_t chr, uint8_t size, uint8_t mode) +{ + uint8_t temp, t, t1; + uint8_t y0 = y; + uint8_t csize = (size / 8 + ((size % 8) ? 1 : 0)) * (size / 2); /* get size */ + + chr = chr - ' '; /* get index */ + for (t = 0; t < csize; t++) /* write size */ + { + if (size == 12) /* if size 12 */ + { + temp = gsc_ssd1306_ascii_1206[chr][t]; /* get ascii 1206 */ + } + else if (size == 16) /* if size 16 */ + { + temp = gsc_ssd1306_ascii_1608[chr][t]; /* get ascii 1608 */ + } + else if(size == 24) /* if size 24 */ + { + temp = gsc_ssd1306_ascii_2412[chr][t]; /* get ascii 2412 */ + } + else + { + return 1; /* return error */ + } + for (t1 = 0; t1 < 8; t1++) /* write one line */ + { + if ((temp & 0x80) != 0) /* if 1 */ + { + if (a_ssd1306_gram_draw_point(handle, x, y, mode) != 0) /* draw point */ + { + return 1; /* return error */ + } + } + else + { + if (a_ssd1306_gram_draw_point(handle, x, y, !mode) != 0) /* draw point */ + { + return 1; /* return error */ + } + } + temp <<= 1; /* left shift 1 */ + y++; + if ((y - y0) == size) /* reset size */ + { + y = y0; /* set y */ + x++; /* x++ */ + + break; /* break */ + } + } + } + + return 0; /* success return 0 */ +} + +/** + * @brief clear the screen + * @param[in] *handle points to an ssd1306 handle structure + * @return status code + * - 0 success + * - 1 clear failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_clear(ssd1306_handle_t *handle) +{ + uint8_t i; + uint8_t n; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + + for (i = 0; i < 8; i++) /* write 8 page */ + { + if (a_ssd1306_write_byte(handle, SSD1306_CMD_PAGE_ADDR+i, SSD1306_CMD) != 0) /* set page */ + { + handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */ + + return 1; /* return error */ + } + if (a_ssd1306_write_byte(handle, SSD1306_CMD_LOWER_COLUMN_START_ADDRESS, SSD1306_CMD) != 0) /* set lower column 0 */ + { + handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */ + + return 1; /* return error */ + } + if (a_ssd1306_write_byte(handle, SSD1306_CMD_HIGHER_COLUMN_START_ADDRESS, SSD1306_CMD) != 0) /* set higher column 0 */ + { + handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */ + + return 1; /* return error */ + } + for (n = 0; n < 128; n++) /* write 128 */ + { + handle->gram[n][i] = 0x00; /* set black */ + if (a_ssd1306_write_byte(handle, handle->gram[n][i], SSD1306_DATA) != 0) /* write data */ + { + handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */ + + return 1; /* return error */ + } + } + } + + return 0; /* success return 0 */ +} + +/** + * @brief update the gram data + * @param[in] *handle points to an ssd1306 handle structure + * @return status code + * - 0 success + * - 1 gram update failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_gram_update(ssd1306_handle_t *handle) +{ + uint8_t i; + uint8_t n; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + + for (i = 0; i < 8; i++) /* write 8 page */ + { + if (a_ssd1306_write_byte(handle, SSD1306_CMD_PAGE_ADDR+i, SSD1306_CMD) != 0) /* set page */ + { + handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */ + + return 1; /* return error */ + } + if (a_ssd1306_write_byte(handle, SSD1306_CMD_LOWER_COLUMN_START_ADDRESS, SSD1306_CMD) != 0) /* set lower column 0 */ + { + handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */ + + return 1; /* return error */ + } + if (a_ssd1306_write_byte(handle, SSD1306_CMD_HIGHER_COLUMN_START_ADDRESS, SSD1306_CMD) != 0) /* set higher column 0 */ + { + handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */ + + return 1; /* return error */ + } + for (n = 0; n < 128; n++) /* write 128 */ + { + if (a_ssd1306_write_byte(handle, handle->gram[n][i], SSD1306_DATA) != 0) /* write data */ + { + handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */ + + return 1; /* return error */ + } + } + } + + return 0; /* success return 0 */ +} + +/** + * @brief write a point + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] x is the coordinate x + * @param[in] y is the coordinate y + * @param[in] data is the write data + * @return status code + * - 0 success + * - 1 write point failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 x or y is invalid + * @note none + */ +uint8_t ssd1306_write_point(ssd1306_handle_t *handle, uint8_t x, uint8_t y, uint8_t data) +{ + uint8_t pos; + uint8_t bx; + uint8_t temp = 0; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if ((x > 127) || (y > 63)) /* check x, y */ + { + handle->debug_print("ssd1306: x or y is invalid.\n"); /* x or y is invalid */ + + return 4; /* return error */ + } + + pos = y / 8; /* get y page */ + bx = y % 8; /* get y point */ + temp = 1 << bx; /* set data */ + if (data != 0) /* check the data */ + { + handle->gram[x][pos] |= temp; /* set 1 */ + } + else + { + handle->gram[x][pos] &= ~temp; /* set 0 */ + } + if (a_ssd1306_write_byte(handle, SSD1306_CMD_PAGE_ADDR + pos, SSD1306_CMD) != 0) /* write page addr */ + { + handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */ + + return 1; /* return error */ + } + if (a_ssd1306_write_byte(handle, SSD1306_CMD_LOWER_COLUMN_START_ADDRESS|(x&0x0F), SSD1306_CMD) != 0) /* write lower column */ + { + handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */ + + return 1; /* return error */ + } + if (a_ssd1306_write_byte(handle, SSD1306_CMD_HIGHER_COLUMN_START_ADDRESS|((x>4)&0x0F), SSD1306_CMD) != 0) /* write higher column */ + { + handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */ + + return 1; /* return error */ + } + if (a_ssd1306_write_byte(handle, handle->gram[x][pos], SSD1306_DATA) != 0) /* write data */ + { + handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */ + + return 1; /* return error */ + } + else + { + return 0; /* success return 0 */ + } +} + +/** + * @brief read a point + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] x is the coordinate x + * @param[in] y is the coordinate y + * @param[out] *data points to a data buffer + * @return status code + * - 0 success + * - 1 read point failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 x or y is invalid + * @note none + */ +uint8_t ssd1306_read_point(ssd1306_handle_t *handle, uint8_t x, uint8_t y, uint8_t *data) +{ + uint8_t pos; + uint8_t bx; + uint8_t temp = 0; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if ((x > 127) || (y > 63)) /* check x, y */ + { + handle->debug_print("ssd1306: x or y is invalid.\n"); /* x or y is invalid */ + + return 4; /* return error */ + } + + pos = y / 8; /* get y page */ + bx = y % 8; /* get y point */ + temp = 1 << bx; /* set data */ + if ((handle->gram[x][pos] & temp) != 0) /* get data */ + { + *data = 1; /* set 1 */ + } + else + { + *data = 0; /* set 0 */ + } + + return 0; /* success return 0 */ +} + +/** + * @brief write a point in the gram + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] x is the coordinate x + * @param[in] y is the coordinate y + * @param[in] data is the write data + * @return status code + * - 0 success + * - 1 gram write point failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 x or y is invalid + * @note none + */ +uint8_t ssd1306_gram_write_point(ssd1306_handle_t *handle, uint8_t x, uint8_t y, uint8_t data) +{ + uint8_t pos; + uint8_t bx; + uint8_t temp = 0; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if ((x > 127) || (y > 63)) /* check x, y */ + { + handle->debug_print("ssd1306: x or y is invalid.\n"); /* x or y is invalid */ + + return 4; /* return error */ + } + + pos = y / 8; /* get y page */ + bx = y % 8; /* get y point */ + temp = 1 << bx; /* set data */ + if (data != 0) /* if 1 */ + { + handle->gram[x][pos] |= temp; /* set 1 */ + } + else + { + handle->gram[x][pos] &= ~temp; /* set 0 */ + } + + return 0; /* success return 0 */ +} + +/** + * @brief read a point from the gram + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] x is the coordinate x + * @param[in] y is the coordinate y + * @param[out] *data points to a data buffer + * @return status code + * - 0 success + * - 1 gram read point failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 x or y is invalid + * @note none + */ +uint8_t ssd1306_gram_read_point(ssd1306_handle_t *handle, uint8_t x, uint8_t y, uint8_t *data) +{ + uint8_t pos; + uint8_t bx; + uint8_t temp = 0; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if ((x > 127) || (y > 63)) /* check x, y */ + { + handle->debug_print("ssd1306: x or y is invalid.\n"); /* x or y is invalid */ + + return 4; /* return error */ + } + + pos = y / 8; /* get y page */ + bx = y % 8; /* get y point */ + temp = 1 << bx; /* set data */ + if ((handle->gram[x][pos] & temp) != 0) /* get data */ + { + *data = 1; /* set 1 */ + } + else + { + *data = 0; /* set 0 */ + } + + return 0; /* success return 0 */ +} + +/** + * @brief draw a string in the gram + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] x is the coordinate x + * @param[in] y is the coordinate y + * @param[in] *str points to a write string address + * @param[in] len is the length of the string + * @param[in] color is the display color + * @param[in] font is the display font size + * @return status code + * - 0 success + * - 1 gram write string failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 x or y is invalid + * @note none + */ +uint8_t ssd1306_gram_write_string(ssd1306_handle_t *handle, uint8_t x, uint8_t y, char *str, uint16_t len, uint8_t color, ssd1306_font_t font) +{ + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if((x > 127) || (y > 63)) /* check x, y */ + { + handle->debug_print("ssd1306: x or y is invalid.\n"); /* x or y is invalid */ + + return 4; /* return error */ + } + + while ((len != 0) && (*str <= '~') && (*str >= ' ')) /* write all string */ + { + if (x > (127 - (font / 2))) /* check x point */ + { + x = 0; /* set x */ + y += (uint8_t)font; /* set next row */ + } + if (y > (63 - font)) /* check y pont */ + { + y = x = 0; /* reset to 0,0 */ + } + if (a_ssd1306_gram_show_char(handle, x, y, *str, font, color) != 0) /* show a char */ + { + return 1; /* return error */ + } + x += (uint8_t)(font / 2); /* x + font/2 */ + str++; /* str address++ */ + len--; /* str length-- */ + } + + return 0; /* success return 0 */ +} + +/** + * @brief fill a rectangle in the gram + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] left is the left coordinate x + * @param[in] top is the top coordinate y + * @param[in] right is the right coordinate x + * @param[in] bottom is the bottom coordinate y + * @param[in] color is the display color + * @return status code + * - 0 success + * - 1 gram fill rect failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 left or top is invalid + * - 5 right or bottom is invalid + * - 6 left > right or top > bottom + * @note none + */ +uint8_t ssd1306_gram_fill_rect(ssd1306_handle_t *handle, uint8_t left, uint8_t top, uint8_t right, uint8_t bottom, uint8_t color) +{ + uint8_t x, y; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if ((left > 127) || (top > 63)) /* check left top */ + { + handle->debug_print("ssd1306: left or top is invalid.\n"); /* left or top is invalid */ + + return 4; /* return error */ + } + if ((right > 127) || (bottom > 63)) /* check right bottom */ + { + handle->debug_print("ssd1306: right or bottom is invalid.\n"); /* right or bottom is invalid */ + + return 5; /* return error */ + } + if ((left > right) || (top > bottom)) /* check left right top bottom */ + { + handle->debug_print("ssd1306: left > right or top > bottom.\n"); /* left > right or top > bottom */ + + return 6; /* return error */ + } + + for (x = left; x <= right; x++) /* write x */ + { + for (y = top; y <= bottom; y++) /* write y */ + { + if (a_ssd1306_gram_draw_point(handle, x, y, color) != 0) /* draw point */ + { + return 1; /* return error */ + } + } + } + + return 0; /* return error */ +} + +/** + * @brief draw a picture in the gram + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] left is the left coordinate x + * @param[in] top is the top coordinate y + * @param[in] right is the right coordinate x + * @param[in] bottom is the bottom coordinate y + * @param[in] *img points to an image buffer + * @return status code + * - 0 success + * - 1 gram draw picture failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 left or top is invalid + * - 5 right or bottom is invalid + * - 6 left > right or top > bottom + * @note none + */ +uint8_t ssd1306_gram_draw_picture(ssd1306_handle_t *handle, uint8_t left, uint8_t top, uint8_t right, uint8_t bottom, uint8_t *img) +{ + uint8_t x, y; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if ((left > 127) || (top > 63)) /* check left top */ + { + handle->debug_print("ssd1306: left or top is invalid.\n"); /* left or top is invalid */ + + return 4; /* return error */ + } + if ((right > 127) || (bottom > 63)) /* check right bottom */ + { + handle->debug_print("ssd1306: right or bottom is invalid.\n"); /* right or bottom is invalid */ + + return 5; /* return error */ + } + if ((left > right) || (top > bottom)) /* check left right top bottom */ + { + handle->debug_print("ssd1306: left > right or top > bottom.\n"); /* left > right or top > bottom */ + + return 6; /* return error */ + } + + for (x = left; x <= right; x++) /* write x */ + { + for (y = top; y <= bottom; y++) /* write y */ + { + if (a_ssd1306_gram_draw_point(handle, x, y, *img) != 0) /* draw point */ + { + return 1; /* return error */ + } + img++; /* img++ */ + } + } + + return 0; /* succeed return 0 */ +} + +/** + * @brief initialize the chip + * @param[in] *handle points to an ssd1306 handle structure + * @return status code + * - 0 success + * - 1 iic or spi initialization failed + * - 2 handle is NULL + * - 3 linked functions is NULL + * - 4 reset failed + * - 5 command && data init failed + * - 6 interface param is invalid + * @note none + */ +uint8_t ssd1306_init(ssd1306_handle_t *handle) +{ + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->debug_print == NULL) /* check debug_print */ + { + return 3; /* return error */ + } + if (handle->iic_init == NULL) /* check iic_init */ + { + handle->debug_print("ssd1306: iic_init is null.\n"); /* iic_init is null */ + + return 3; /* return error */ + } + if (handle->iic_deinit == NULL) /* check iic_deinit */ + { + handle->debug_print("ssd1306: iic_deinit is null.\n"); /* iic_deinit is null */ + + return 3; /* return error */ + } + if (handle->iic_write == NULL) /* check iic_write */ + { + handle->debug_print("ssd1306: iic_write is null.\n"); /* iic_write is null */ + + return 3; /* return error */ + } + if (handle->spi_init == NULL) /* check spi_init */ + { + handle->debug_print("ssd1306: spi_init is null.\n"); /* spi_init is null */ + + return 3; /* return error */ + } + if (handle->spi_deinit == NULL) /* check spi_deinit */ + { + handle->debug_print("ssd1306: spi_deinit is null.\n"); /* spi_deinit is null */ + + return 3; /* return error */ + } + if (handle->spi_write_cmd == NULL) /* check spi_write_cmd */ + { + handle->debug_print("ssd1306: spi_write_cmd is null.\n"); /* spi_write_cmd is null */ + + return 3; /* return error */ + } + if (handle->delay_ms == NULL) /* check delay_ms */ + { + handle->debug_print("ssd1306: delay_ms is null.\n"); /* delay_ms is null */ + + return 3; /* return error */ + } + if (handle->spi_cmd_data_gpio_init == NULL) /* check spi_cmd_data_gpio_init */ + { + handle->debug_print("ssd1306: spi_cmd_data_gpio_init is null.\n"); /* spi_cmd_data_gpio_init is null */ + + return 3; /* return error */ + } + if (handle->spi_cmd_data_gpio_deinit == NULL) /* check spi_cmd_data_gpio_deinit */ + { + handle->debug_print("ssd1306: spi_cmd_data_gpio_deinit is null.\n"); /* spi_cmd_data_gpio_deinit is null */ + + return 3; /* return error */ + } + if (handle->spi_cmd_data_gpio_write == NULL) /* check spi_cmd_data_gpio_write */ + { + handle->debug_print("ssd1306: spi_cmd_data_gpio_write is null.\n"); /* spi_cmd_data_gpio_write is null */ + + return 3; /* return error */ + } + if (handle->reset_gpio_init == NULL) /* check reset_gpio_init */ + { + handle->debug_print("ssd1306: reset_gpio_init is null.\n"); /* reset_gpio_init is null */ + + return 3; /* return error */ + } + if (handle->reset_gpio_deinit == NULL) /* check reset_gpio_deinit */ + { + handle->debug_print("ssd1306: reset_gpio_deinit is null.\n"); /* reset_gpio_deinit is null */ + + return 3; /* return error */ + } + if(handle->reset_gpio_write == NULL) /* check reset_gpio_write */ + { + handle->debug_print("ssd1306: reset_gpio_write is null.\n"); /* reset_gpio_write is null */ + + return 3; /* return error */ + } + + if (handle->spi_cmd_data_gpio_init() != 0) /* check spi_cmd_data_gpio_init */ + { + handle->debug_print("ssd1306: spi cmd data gpio init failed.\n"); /* spi cmd data gpio init failed */ + + return 5; /* return error */ + } + if (handle->reset_gpio_init() != 0) /* reset gpio init */ + { + handle->debug_print("ssd1306: reset gpio init failed.\n"); /* reset gpio init failed */ + (void)handle->spi_cmd_data_gpio_deinit(); /* spi_cmd_data_gpio_deinit */ + + return 4; /* return error */ + } + if (handle->reset_gpio_write(0) != 0) /* write 0 */ + { + handle->debug_print("ssd1306: reset gpio write failed.\n"); /* reset gpio write failed */ + (void)handle->spi_cmd_data_gpio_deinit(); /* spi_cmd_data_gpio_deinit */ + (void)handle->reset_gpio_deinit(); /* reset_gpio_deinit */ + + return 4; /* return error */ + } + handle->delay_ms(100); /* delay 100 ms */ + if (handle->reset_gpio_write(1) != 0) /* write 1 */ + { + handle->debug_print("ssd1306: reset gpio write failed.\n"); /* reset gpio write failed */ + (void)handle->spi_cmd_data_gpio_deinit(); /* spi_cmd_data_gpio_deinit */ + (void)handle->reset_gpio_deinit(); /* reset_gpio_deinit */ + + return 4; /* return error */ + } + if (handle->iic_spi == SSD1306_INTERFACE_IIC) /* if iic interface */ + { + if (handle->iic_init() != 0) /* iic init */ + { + handle->debug_print("ssd1306: iic init failed.\n"); /* iic init failed */ + (void)handle->spi_cmd_data_gpio_deinit(); /* spi_cmd_data_gpio_deinit */ + (void)handle->reset_gpio_deinit(); /* reset_gpio_deinit */ + + return 1; /* return error */ + } + } + else if (handle->iic_spi == SSD1306_INTERFACE_SPI) /* if spi interface */ + { + if (handle->spi_init() != 0) /* spi init */ + { + handle->debug_print("ssd1306: spi init failed.\n"); /* spi init failed */ + (void)handle->spi_cmd_data_gpio_deinit(); /* spi_cmd_data_gpio_deinit */ + (void)handle->reset_gpio_deinit(); /* reset_gpio_deinit */ + + return 1; /* return error */ + } + } + else + { + handle->debug_print("ssd1306: interface is invalid.\n"); /* interface is invalid */ + (void)handle->spi_cmd_data_gpio_deinit(); /* spi_cmd_data_gpio_deinit */ + (void)handle->reset_gpio_deinit(); /* reset_gpio_deinit */ + + return 6; /* return error */ + } + handle->inited = 1; /* flag inited */ + + return 0; /* success return 0 */ +} + +/** + * @brief close the chip + * @param[in] *handle points to an ssd1306 handle structure + * @return status code + * - 0 success + * - 1 iic or spi deinit failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 power down failed + * - 5 reset gpio deinit failed + * - 6 command && data deinit failed + * - 7 interface param is invalid + * @note none + */ +uint8_t ssd1306_deinit(ssd1306_handle_t *handle) +{ + uint8_t buf[2]; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + + buf[0] = SSD1306_CMD_CHARGE_PUMP_SETTING; /* charge pump off */ + buf[1] = 0x10 | (0 << 2); /* set charge pump */ + if (a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD) != 0) /* write command */ + { + handle->debug_print("ssd1306: write command failed.\n"); /* write command failed */ + + return 4; /* return error */ + } + if (a_ssd1306_write_byte(handle, SSD1306_CMD_DISPLAY_OFF, SSD1306_CMD) != 0) /* write display off */ + { + handle->debug_print("ssd1306: write command failed.\n"); /* write command failed */ + + return 4; /* return error */ + } + if (handle->reset_gpio_deinit() != 0) /* reset gpio deinit */ + { + handle->debug_print("ssd1306: reset gpio deinit failed.\n"); /* reset gpio deinit failed */ + + return 5; /* return error */ + } + if (handle->spi_cmd_data_gpio_deinit() != 0) /* spi cmd data gpio deinit */ + { + handle->debug_print("ssd1306: spi cmd data gpio deinit failed.\n"); /* spi cmd data gpio deinit failed */ + + return 6; /* return error */ + } + if (handle->iic_spi == SSD1306_INTERFACE_IIC) /* if iic interface */ + { + if (handle->iic_deinit() != 0) /* iic deinit */ + { + handle->debug_print("ssd1306: iic deinit failed.\n"); /* iic deinit failed */ + + return 1; /* return error */ + } + } + else if (handle->iic_spi == SSD1306_INTERFACE_SPI) /* if spi interface */ + { + if (handle->spi_deinit() != 0) /* spi deinit */ + { + handle->debug_print("ssd1306: spi deinit failed.\n"); /* spi deinit failed */ + + return 1; /* return error */ + } + } + else + { + handle->debug_print("ssd1306: interface is invalid.\n"); /* interface is invalid */ + + return 7; /* return error */ + } + handle->inited = 0; /* flag close */ + + return 0; /* success return 0 */ +} + +/** + * @brief set the chip interface + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] interface is the chip interface + * @return status code + * - 0 success + * - 2 handle is NULL + * @note none + */ +uint8_t ssd1306_set_interface(ssd1306_handle_t *handle, ssd1306_interface_t interface) +{ + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + + handle->iic_spi = (uint8_t)interface; /* set interface */ + + return 0; /* success return 0 */ +} + +/** + * @brief get the chip interface + * @param[in] *handle points to an ssd1306 handle structure + * @param[out] *interface points to a chip interface buffer + * @return status code + * - 0 success + * - 2 handle is NULL + * @note none + */ +uint8_t ssd1306_get_interface(ssd1306_handle_t *handle, ssd1306_interface_t *interface) +{ + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + + *interface = (ssd1306_interface_t)(handle->iic_spi); /* get interface */ + + return 0; /* success return 0 */ +} + +/** + * @brief set the chip iic address + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] addr_pin is the iic address + * @return status code + * - 0 success + * - 2 handle is NULL + * @note none + */ +uint8_t ssd1306_set_addr_pin(ssd1306_handle_t *handle, ssd1306_address_t addr_pin) +{ + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + + handle->iic_addr = (uint8_t)addr_pin; /* set addr pin */ + + return 0; /* success return 0 */ +} + +/** + * @brief get the chip iic address + * @param[in] *handle points to an ssd1306 handle structure + * @param[out] *addr_pin points to an iic address buffer + * @return status code + * - 0 success + * - 2 handle is NULL + * @note none + */ +uint8_t ssd1306_get_addr_pin(ssd1306_handle_t *handle, ssd1306_address_t *addr_pin) +{ + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + + *addr_pin = (ssd1306_address_t)(handle->iic_addr); /* set address */ + + return 0; /* success return 0 */ +} + +/** + * @brief set the low column start address + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] addr is the low column start address + * @return status code + * - 0 success + * - 1 set low column start address failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 addr is invalid + * @note addr <= 0xF + */ +uint8_t ssd1306_set_low_column_start_address(ssd1306_handle_t *handle, uint8_t addr) +{ + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if (addr > 0x0F) /* check addr */ + { + handle->debug_print("ssd1306: addr is invalid.\n"); /* addr is invalid */ + + return 4; /* return error */ + } + + return a_ssd1306_write_byte(handle, SSD1306_CMD_LOWER_COLUMN_START_ADDRESS|(addr&0x0F), SSD1306_CMD); /* write command */ +} + +/** + * @brief set the high column start address + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] addr is the high column start address + * @return status code + * - 0 success + * - 1 set high column start address failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 addr is invalid + * @note addr <= 0xF + */ +uint8_t ssd1306_set_high_column_start_address(ssd1306_handle_t *handle, uint8_t addr) +{ + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if (addr > 0x0F) /* check addr */ + { + handle->debug_print("ssd1306: addr is invalid.\n"); /* addr is invalid */ + + return 4; /* return error */ + } + + return a_ssd1306_write_byte(handle, SSD1306_CMD_HIGHER_COLUMN_START_ADDRESS|(addr&0x0F), SSD1306_CMD); /* write command */ +} + +/** + * @brief set the memory addressing mode + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] mode is the memory addressing mode + * @return status code + * - 0 success + * - 1 set memory addressing mode failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_memory_addressing_mode(ssd1306_handle_t *handle, ssd1306_memory_addressing_mode_t mode) +{ + uint8_t buf[2]; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + + buf[0] = SSD1306_CMD_MEMORY_ADDRESSING_MODE; /* set command mode */ + buf[1] = mode; /* set mode */ + + return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */ +} + +/** + * @brief set the column address range + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] start_addr is the column start address + * @param[in] end_addr is the column end address + * @return status code + * - 0 success + * - 1 set column address range failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 start addr is invalid + * - 5 end addr is invalid + * @note start addr and end addr can't be over 0x7F + */ +uint8_t ssd1306_set_column_address_range(ssd1306_handle_t *handle, uint8_t start_addr, uint8_t end_addr) +{ + uint8_t buf[3]; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if (start_addr > 0x7F) /* check start addr */ + { + handle->debug_print("ssd1306: start addr is invalid.\n"); /* start addr is invalid */ + + return 4; /* return error */ + } + if (end_addr > 0x7F) /* check end addr */ + { + handle->debug_print("ssd1306: end addr is invalid.\n"); /* end addr is invalid */ + + return 5; /* return error */ + } + + buf[0] = SSD1306_CMD_SET_COLUMN_ADDRESS; /* set command */ + buf[1] = start_addr & 0x7F; /* set start address */ + buf[2] = end_addr & 0x7F; /* set end address */ + + return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 3, SSD1306_CMD); /* write command */ +} + +/** + * @brief set the page address range + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] start_addr is the page start address + * @param[in] end_addr is the page end address + * @return status code + * - 0 success + * - 1 set page address range failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 start addr is invalid + * - 5 end addr is invalid + * @note start addr and end addr can't be over 0x07 + */ +uint8_t ssd1306_set_page_address_range(ssd1306_handle_t *handle, uint8_t start_addr, uint8_t end_addr) +{ + uint8_t buf[3]; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if (start_addr > 0x07) /* check start addr */ + { + handle->debug_print("ssd1306: start addr is invalid.\n"); /* start addr is invalid */ + + return 4; /* return error */ + } + if (end_addr > 0x07) /* check end addr */ + { + handle->debug_print("ssd1306: end addr is invalid.\n"); /* end_addr is invalid */ + + return 5; /* return error */ + } + + buf[0] = SSD1306_CMD_SET_PAGE_ADDRESS; /* set command */ + buf[1] = start_addr & 0x07; /* set start address */ + buf[2] = end_addr & 0x07; /* set end address */ + + return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 3, SSD1306_CMD); /* write command */ +} + +/** + * @brief set the fade blinking mode + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] mode is the fade blinking mode + * @param[in] frames is the fade or blinking frames + * @return status code + * - 0 success + * - 1 set fade blinking mode failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 frames is invalid + * @note frames max is 0x0F and div is (frames + 1) * 8 + */ +uint8_t ssd1306_set_fade_blinking_mode(ssd1306_handle_t *handle, ssd1306_fade_blinking_mode_t mode, uint8_t frames) +{ + uint8_t buf[2]; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if (frames> 0x0F) /* check frames */ + { + handle->debug_print("ssd1306: frames is invalid.\n"); /* frames is invalid */ + + return 4; /* return error */ + } + + buf[0] = SSD1306_CMD_SET_FADE_OUT_AND_BLINKING; /* set command */ + buf[1] = (uint8_t)((mode << 4) | (frames & 0x0F)); /* set mode */ + + return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */ +} + +/** + * @brief set the right horizontal scroll + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] start_page_addr is the start page address + * @param[in] end_page_addr is the end page address + * @param[in] frames is the scroll frames + * @return status code + * - 0 success + * - 1 set right horizontal scroll failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 start page addr is invalid + * - 5 end page addr is invalid + * @note start_page_addr <= 0x07, end_page_addr <= 0x07 + */ +uint8_t ssd1306_set_right_horizontal_scroll(ssd1306_handle_t *handle, uint8_t start_page_addr, uint8_t end_page_addr, + ssd1306_scroll_frame_t frames) +{ + uint8_t buf[7]; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if (start_page_addr > 0x07) /* check start_page_addr */ + { + handle->debug_print("ssd1306: start page addr is invalid.\n"); /* start page addr is invalid */ + + return 4; /* return error */ + } + if (end_page_addr > 0x07) /* check end_page_addr */ + { + handle->debug_print("ssd1306: end page addr is invalid.\n"); /* end page addr is invalid */ + + return 5; /* return error */ + } + + buf[0] = SSD1306_CMD_RIGHT_HORIZONTAL_SCROLL; /* set command */ + buf[1] = 0x00; /* set null */ + buf[2] = start_page_addr & 0x07; /* set start page address */ + buf[3] = frames & 0x07; /* set frames */ + buf[4] = end_page_addr & 0x07; /* set end page address */ + buf[5] = 0x00; /* set null */ + buf[6] = 0xFF; /* set frame end */ + + return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 7, SSD1306_CMD); /* write command */ +} + +/** + * @brief set the left horizontal scroll + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] start_page_addr is the start page address + * @param[in] end_page_addr is the end page address + * @param[in] frames is the scroll frames + * @return status code + * - 0 success + * - 1 set left horizontal scroll failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 start_page_addr is invalid + * - 5 end_page_addr is invalid + * @note start_page_addr <= 0x07, end_page_addr <= 0x07 + */ +uint8_t ssd1306_set_left_horizontal_scroll(ssd1306_handle_t *handle, uint8_t start_page_addr, uint8_t end_page_addr, + ssd1306_scroll_frame_t frames) +{ + uint8_t buf[7]; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if (start_page_addr > 0x07) /* check start_page_addr */ + { + handle->debug_print("ssd1306: start_page_addr is invalid.\n"); /* start_page_addr is invalid */ + + return 4; /* return error */ + } + if (end_page_addr > 0x07) /* check end_page_addr */ + { + handle->debug_print("ssd1306: end_page_addr is invalid.\n"); /* end_page_addr is invalid */ + + return 5; /* return error */ + } + + buf[0] = SSD1306_CMD_LEFT_HORIZONTAL_SCROLL; /* set command */ + buf[1] = 0x00; /* set null */ + buf[2] = start_page_addr & 0x07; /* set end page addr */ + buf[3] = frames & 0x07; /* set frames */ + buf[4] = end_page_addr & 0x07; /* set end page addr */ + buf[5] = 0x00; /* set null */ + buf[6] = 0xFF; /* set frame end */ + + return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 7, SSD1306_CMD); /* write command */ +} + +/** + * @brief set the vertical right horizontal scroll + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] start_page_addr is the start page address + * @param[in] end_page_addr is the end page address + * @param[in] rows is the row address + * @param[in] frames is the scroll frames + * @return status code + * - 0 success + * - 1 set vertical right horizontal scroll failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 start_page_addr is invalid + * - 5 end_page_addr is invalid + * - 6 rows is invalid + * @note start_page_addr <= 0x07, end_page_addr <= 0x07, rows <= 0x3F + */ +uint8_t ssd1306_set_vertical_right_horizontal_scroll(ssd1306_handle_t *handle, uint8_t start_page_addr, uint8_t end_page_addr, + uint8_t rows, ssd1306_scroll_frame_t frames) +{ + uint8_t buf[6]; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if (start_page_addr > 0x07) /* check start_page_addr */ + { + handle->debug_print("ssd1306: start_page_addr is invalid.\n"); /* start_page_addr is invalid */ + + return 4; /* return error */ + } + if (end_page_addr > 0x07) /* check end page addr */ + { + handle->debug_print("ssd1306: end_page_addr is invalid.\n"); /* end_page_addr is invalid */ + + return 5; /* return error */ + } + if (rows > 0x3F) /* check rows */ + { + handle->debug_print("ssd1306: rows is invalid.\n"); /* rows is invalid */ + + return 6; /* return error */ + } + + buf[0] = SSD1306_CMD_VERTICAL_RIGHT_HORIZONTAL_SCROLL; /* set command */ + buf[1] = 0x00; /* set null */ + buf[2] = start_page_addr & 0x07; /* set start page addr */ + buf[3] = frames & 0x07; /* set frames */ + buf[4] = end_page_addr & 0x07; /* set end page addr */ + buf[5] = rows & 0x3F; /* set rows */ + + return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 6, SSD1306_CMD); /* write command */ +} + +/** + * @brief set the vertical left horizontal scroll + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] start_page_addr is the start page address + * @param[in] end_page_addr is the end page address + * @param[in] rows is the row address + * @param[in] frames is the scroll frames + * @return status code + * - 0 success + * - 1 set vertical left horizontal scroll failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 start_page_addr is invalid + * - 5 end_page_addr is invalid + * - 6 rows is invalid + * @note start_page_addr <= 0x07, end_page_addr <= 0x07, rows <= 0x3F + */ +uint8_t ssd1306_set_vertical_left_horizontal_scroll(ssd1306_handle_t *handle, uint8_t start_page_addr, uint8_t end_page_addr, + uint8_t rows, ssd1306_scroll_frame_t frames) +{ + uint8_t buf[6]; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if (start_page_addr > 0x07) /* check start_page_addr */ + { + handle->debug_print("ssd1306: start_page_addr is invalid.\n"); /* start_page_addr is invalid */ + + return 4; /* return error */ + } + if (end_page_addr > 0x07) /* check end_page_addr */ + { + handle->debug_print("ssd1306: end_page_addr is invalid.\n"); /* end_page_addr is invalid */ + + return 5; /* return error */ + } + if (rows > 0x3F) /* check rows */ + { + handle->debug_print("ssd1306: rows is invalid.\n"); /* rows is invalid */ + + return 6; /* return error */ + } + + buf[0] = SSD1306_CMD_VERTICAL_LEFT_HORIZONTAL_SCROLL; /* set command */ + buf[1] = 0x00; /* set null */ + buf[2] = start_page_addr & 0x07; /* set start page addr */ + buf[3] = frames & 0x07; /* set frames */ + buf[4] = end_page_addr & 0x07; /* set end page addr */ + buf[5] = rows & 0x3F; /* set rows */ + + return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 6, SSD1306_CMD); /* write command */ +} + +/** + * @brief deactivate the scroll + * @param[in] *handle points to an ssd1306 handle structure + * @return status code + * - 0 success + * - 1 deactivate scroll failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_deactivate_scroll(ssd1306_handle_t *handle) +{ + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + + return a_ssd1306_write_byte(handle, SSD1306_CMD_DEACTIVATE_SCROLL, SSD1306_CMD); /* write command */ +} + +/** + * @brief activate the scroll + * @param[in] *handle points to an ssd1306 handle structure + * @return status code + * - 0 success + * - 1 activate scroll failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_activate_scroll(ssd1306_handle_t *handle) +{ + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + + return a_ssd1306_write_byte(handle, SSD1306_CMD_ACTIVATE_SCROLL, SSD1306_CMD); /* write command */ +} + +/** + * @brief set the display start line + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] l is the start line + * @return status code + * - 0 success + * - 1 set display start line failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 line is invalid + * @note line <= 0x3F + */ +uint8_t ssd1306_set_display_start_line(ssd1306_handle_t *handle, uint8_t l) +{ + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if (l > 0x3F) /* check line */ + { + handle->debug_print("ssd1306: line is invalid.\n"); /* line is invalid */ + + return 4; /* return error */ + } + + return a_ssd1306_write_byte(handle, SSD1306_CMD_DISPLAY_START_LINE|(l&0x3F), SSD1306_CMD); /* write command */ +} + +/** + * @brief set the display contrast + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] contrast is the display contrast + * @return status code + * - 0 success + * - 1 set contrast failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_contrast(ssd1306_handle_t *handle, uint8_t contrast) +{ + uint8_t buf[2]; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + + buf[0] = SSD1306_CMD_CONTRAST_CONTROL; /* set command */ + buf[1] = contrast; /* set contrast */ + + return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */ +} + +/** + * @brief enable or disable the charge pump + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] enable is a bool value + * @return status code + * - 0 success + * - 1 set charge pump failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_charge_pump(ssd1306_handle_t *handle, ssd1306_charge_pump_t enable) +{ + uint8_t buf[2]; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + + buf[0] = SSD1306_CMD_CHARGE_PUMP_SETTING; /* set command */ + buf[1] = (uint8_t)(0x10 | (enable << 2)); /* set charge pump */ + + return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */ +} + +/** + * @brief set the segment remap + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] remap is the segment remap param + * @return status code + * - 0 success + * - 1 set segment remap failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_segment_remap(ssd1306_handle_t *handle, ssd1306_segment_column_remap_t remap) +{ + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + + if (remap != 0) /* check remap */ + { + return a_ssd1306_write_byte(handle, SSD1306_CMD_COLUMN_127_MAPPED_TO_SEG0, SSD1306_CMD); /* write remap */ + } + else + { + return a_ssd1306_write_byte(handle, SSD1306_CMD_COLUMN_0_MAPPED_TO_SEG0, SSD1306_CMD); /* write remap */ + } +} + +/** + * @brief set the vertical scroll area + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] start_row is the start row + * @param[in] end_row is the end row + * @return status code + * - 0 success + * - 1 set vertical scroll area failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 start_row is invalid + * - 5 end_row is invalid + * - 6 end_row > start_row + * @note start_row <= 0x3F, end_row <= 0x7F, start_row >= end_row + */ +uint8_t ssd1306_set_vertical_scroll_area(ssd1306_handle_t *handle, uint8_t start_row, uint8_t end_row) +{ + uint8_t buf[3]; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if (start_row > 0x3F) /* check start row */ + { + handle->debug_print("ssd1306: start_row is invalid.\n"); /* start_row is invalid */ + + return 4; /* return error */ + } + if (end_row > 0x7F) /* check end_row */ + { + handle->debug_print("ssd1306: end_row is invalid.\n"); /* end_row is invalid */ + + return 5; /* return error */ + } + if (end_row > start_row) /* check start_row and end_row */ + { + handle->debug_print("ssd1306: end_row > start_row.\n"); /* end_row > start_row */ + + return 6; /* return error */ + } + + buf[0] = SSD1306_CMD_VERTICAL_SCROLL_AREA; /* set command */ + buf[1] = start_row; /* set start row */ + buf[2] = end_row; /* set end row */ + + return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 3, SSD1306_CMD); /* write command */ +} + +/** + * @brief enable or disable the entire display + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] enable is a bool value + * @return status code + * - 0 success + * - 1 set entire display failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_entire_display(ssd1306_handle_t *handle, ssd1306_entire_display_t enable) +{ + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + + if (enable != 0) /* if enable */ + { + return a_ssd1306_write_byte(handle, SSD1306_CMD_ENTIRE_DISPLAY_ON, SSD1306_CMD); /* write command */ + } + else + { + return a_ssd1306_write_byte(handle, SSD1306_CMD_ENTIRE_DISPLAY_OFF, SSD1306_CMD); /* write command */ + } +} + +/** + * @brief set the display mode + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] mode is the display mode + * @return status code + * - 0 success + * - 1 set display mode failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_display_mode(ssd1306_handle_t *handle, ssd1306_display_mode_t mode) +{ + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + + if (mode != 0) /* check mode */ + { + return a_ssd1306_write_byte(handle, SSD1306_CMD_INVERSE_DISPLAY, SSD1306_CMD); /* write command */ + } + else + { + return a_ssd1306_write_byte(handle, SSD1306_CMD_NORMAL_DISPLAY, SSD1306_CMD); /* write command */ + } +} + +/** + * @brief set the multiplex ratio + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] multiplex is the multiplex ratio + * @return status code + * - 0 success + * - 1 set multiplex ratio failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 multiplex is too small + * - 5 multiplex is too large + * @note multiplex must be over 0x0E and less than 0x40 + */ +uint8_t ssd1306_set_multiplex_ratio(ssd1306_handle_t *handle, uint8_t multiplex) +{ + uint8_t buf[2]; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if (multiplex < 0x0F) /* check multiplex */ + { + handle->debug_print("ssd1306: multiplex is too small.\n"); /* multiplex is too small */ + + return 4; /* return error */ + } + if (multiplex > 0x3F) /* check multiplex */ + { + handle->debug_print("ssd1306: multiplex is too large.\n"); /* multiplex is too large */ + + return 5; /* return error */ + } + + buf[0] = SSD1306_CMD_MULTIPLEX_RATIO ; /* set command */ + buf[1] = multiplex; /* set multiplex */ + + return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */ +} + +/** + * @brief enable or disable the display + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] on_off is a bool value + * @return status code + * - 0 success + * - 1 set display failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_display(ssd1306_handle_t *handle, ssd1306_display_t on_off) +{ + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + + if (on_off != 0) /* check on off */ + { + return a_ssd1306_write_byte(handle, SSD1306_CMD_DISPLAY_ON, SSD1306_CMD); /* write command */ + } + else + { + return a_ssd1306_write_byte(handle, SSD1306_CMD_DISPLAY_OFF, SSD1306_CMD); /* write command */ + } +} + +/** + * @brief set the page address + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] addr is the page address + * @return status code + * - 0 success + * - 1 set page address failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 addr is invalid + * @note addr <= 0x07 + */ +uint8_t ssd1306_set_page_address(ssd1306_handle_t *handle, uint8_t addr) +{ + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if (addr > 0x07) /* check addr */ + { + handle->debug_print("ssd1306: addr is invalid.\n"); /* addr is invalid */ + + return 4; /* return error */ + } + + return a_ssd1306_write_byte(handle, SSD1306_CMD_PAGE_ADDR|(addr&0x07), SSD1306_CMD); /* write command */ +} + +/** + * @brief set the scan direction + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] dir is the scan direction + * @return status code + * - 0 success + * - 1 set scan direction failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_scan_direction(ssd1306_handle_t *handle, ssd1306_scan_direction_t dir) +{ + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + + if (dir != 0) /* choose dir */ + { + return a_ssd1306_write_byte(handle, SSD1306_CMD_SCAN_DIRECTION_COMN_1_START, SSD1306_CMD); /* write command */ + } + else + { + return a_ssd1306_write_byte(handle, SSD1306_CMD_SCAN_DIRECTION_COM0_START, SSD1306_CMD); /* write command */ + } +} + +/** + * @brief set the display offset + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] offset is the display offset + * @return status code + * - 0 success + * - 1 set display offset failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 offset is invalid + * @note offset <= 0x3F + */ +uint8_t ssd1306_set_display_offset(ssd1306_handle_t *handle, uint8_t offset) +{ + uint8_t buf[2]; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if (offset > 0x3F) /* check offset */ + { + handle->debug_print("ssd1306: offset is invalid.\n"); /* offset is invalid */ + + return 4; /* return error */ + } + + buf[0] = SSD1306_CMD_DISPLAY_OFFSET ; /* set command */ + buf[1] = offset; /* set offset */ + + return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */ +} + +/** + * @brief set the display clock + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] oscillator_frequency is the oscillator frequency + * @param[in] clock_divide is the clock divide + * @return status code + * - 0 success + * - 1 set display clock failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 oscillator frequency is invalid + * - 5 clock divide is invalid + * @note oscillator_frequency <= 0x0F, clock_divide <= 0x0F + */ +uint8_t ssd1306_set_display_clock(ssd1306_handle_t *handle, uint8_t oscillator_frequency, uint8_t clock_divide) +{ + uint8_t buf[2]; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if (oscillator_frequency> 0x0F) /* check oscillator_frequency */ + { + handle->debug_print("ssd1306: oscillator frequency is invalid.\n"); /* oscillator frequency is invalid */ + + return 4; /* return error */ + } + if (clock_divide> 0x0F) /* check clock_divide */ + { + handle->debug_print("ssd1306: clock divide is invalid.\n"); /* clock divide is invalid */ + + return 5; /* return error */ + } + + buf[0] = SSD1306_CMD_DISPLAY_CLOCK_DIVIDE ; /* set command */ + buf[1] = (oscillator_frequency<<4) | clock_divide; /* set oscillator frequency and clock divide */ + + return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */ +} + +/** + * @brief set the display zoom in + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] zoom is the display zoom in + * @return status code + * - 0 success + * - 1 set zoom in failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_zoom_in(ssd1306_handle_t *handle, ssd1306_zoom_in_t zoom) +{ + uint8_t buf[2]; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + + buf[0] = SSD1306_CMD_SET_ZOOM_IN ; /* set command */ + buf[1] = zoom; /* set zoom */ + + return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */ +} + +/** + * @brief set the pre charge period + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] phase1_period is the phase1 period + * @param[in] phase2_period is the phase2 period + * @return status code + * - 0 success + * - 1 set pre charge period failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 phase1 period is invalid + * - 5 phase2 period is invalid + * @note phase1_period <= 0x0F, phase2_period <= 0x0F + */ +uint8_t ssd1306_set_precharge_period(ssd1306_handle_t *handle, uint8_t phase1_period, uint8_t phase2_period) +{ + uint8_t buf[2]; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + if (phase1_period> 0x0F) /* check phase1 period */ + { + handle->debug_print("ssd1306: phase1 period is invalid.\n"); /* phase1 period is invalid */ + + return 4; /* return error */ + } + if (phase2_period> 0x0F) /* check phase2 period */ + { + handle->debug_print("ssd1306: phase2 period is invalid.\n"); /* phase2 period is invalid */ + + return 5; /* return error */ + } + + buf[0] = SSD1306_CMD_PRE_CHARGE_PERIOD; /* set command */ + buf[1] = (phase2_period << 4) | phase1_period; /* set period */ + + return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */ +} + +/** + * @brief set the hardware com pins + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] conf is the pin conf + * @param[in] remap is the left right remap + * @return status code + * - 0 success + * - 1 set com pins hardware conf failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_com_pins_hardware_conf(ssd1306_handle_t *handle, ssd1306_pin_conf_t conf, ssd1306_left_right_remap_t remap) +{ + uint8_t buf[2]; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + + buf[0] = SSD1306_CMD_COM_PINS_CONF; /* set command */ + buf[1] = (uint8_t)((conf<<4) | (remap<<5) |0x02); /* set com pins */ + + return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */ +} + +/** + * @brief set the deselect level + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] level is the deselect level + * @return status code + * - 0 success + * - 1 set deselect level failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_deselect_level(ssd1306_handle_t *handle, ssd1306_deselect_level_t level) +{ + uint8_t buf[2]; + + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + + buf[0] = SSD1306_CMD_COMH_DESLECT_LEVEL; /* set command */ + buf[1] = (uint8_t)(level << 4); /* set level */ + + return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */ +} + +/** + * @brief write the register command + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] *buf points to a data buffer + * @param[in] len is the data length + * @return status code + * - 0 success + * - 1 write failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_write_cmd(ssd1306_handle_t *handle, uint8_t *buf, uint8_t len) +{ + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + + return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, len, SSD1306_CMD); /* write command */ +} + +/** + * @brief write the register data + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] *buf points to a data buffer + * @param[in] len is the data length + * @return status code + * - 0 success + * - 1 write failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_write_data(ssd1306_handle_t *handle, uint8_t *buf, uint8_t len) +{ + if (handle == NULL) /* check handle */ + { + return 2; /* return error */ + } + if (handle->inited != 1) /* check handle initialization */ + { + return 3; /* return error */ + } + + return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, len, SSD1306_DATA); /* write data */ +} + +/** + * @brief get chip's information + * @param[out] *info points to an ssd1306 info structure + * @return status code + * - 0 success + * - 2 handle is NULL + * @note none + */ +uint8_t ssd1306_info(ssd1306_info_t *info) +{ + if (info == NULL) /* check handle */ + { + return 2; /* return error */ + } + + memset(info, 0, sizeof(ssd1306_info_t)); /* initialize ssd1306 info structure */ + strncpy(info->chip_name, CHIP_NAME, 32); /* copy chip name */ + strncpy(info->manufacturer_name, MANUFACTURER_NAME, 32); /* copy manufacturer name */ + strncpy(info->interface, "IIC SPI", 8); /* copy interface name */ + info->supply_voltage_min_v = SUPPLY_VOLTAGE_MIN; /* set minimal supply voltage */ + info->supply_voltage_max_v = SUPPLY_VOLTAGE_MAX; /* set maximum supply voltage */ + info->max_current_ma = MAX_CURRENT; /* set maximum current */ + info->temperature_max = TEMPERATURE_MAX; /* set minimal temperature */ + info->temperature_min = TEMPERATURE_MIN; /* set maximum temperature */ + info->driver_version = DRIVER_VERSION; /* set driver version */ + + return 0; /* success return 0 */ +} diff --git a/app/src/basic/ssd1306/driver_ssd1306.h b/app/src/basic/ssd1306/driver_ssd1306.h new file mode 100644 index 0000000..4d762f5 --- /dev/null +++ b/app/src/basic/ssd1306/driver_ssd1306.h @@ -0,0 +1,1105 @@ +/** + * Copyright (c) 2015 - present LibDriver All rights reserved + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * @file driver_ssd1306.h + * @brief driver ssd1306 header file + * @version 2.0.0 + * @author Shifeng Li + * @date 2021-03-30 + * + *

history

+ * + *
Date Version Author Description + *
2021/03/30 2.0 Shifeng Li format the code + *
2020/12/10 1.0 Shifeng Li first upload + *
+ */ + +#ifndef DRIVER_SSD1306_H +#define DRIVER_SSD1306_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +/** + * @defgroup ssd1306_driver ssd1306 driver function + * @brief ssd1306 driver modules + * @{ + */ + +/** + * @addtogroup ssd1306_base_driver + * @{ + */ + +/** + * @brief ssd1306 interface enumeration definition + */ +typedef enum +{ + SSD1306_INTERFACE_IIC = 0x00, /**< interface iic */ + SSD1306_INTERFACE_SPI = 0x01, /**< interface spi */ +} ssd1306_interface_t; + +/** + * @brief ssd1306 address pin enumeration definition + */ +typedef enum +{ + SSD1306_ADDR_SA0_0 = 0x78, /**< address pin GND */ + SSD1306_ADDR_SA0_1 = 0x7A, /**< address pin VCC */ +} ssd1306_address_t; + +/** + * @brief ssd1306 memory addressing mode enumeration definition + */ +typedef enum +{ + SSD1306_MEMORY_ADDRESSING_MODE_HORIZONTAL = 0x00, /**< horizontal addressing mode */ + SSD1306_MEMORY_ADDRESSING_MODE_VERTICAL = 0x01, /**< vertical addressing mode */ + SSD1306_MEMORY_ADDRESSING_MODE_PAGE = 0x02, /**< page addressing mode */ +} ssd1306_memory_addressing_mode_t; + +/** + * @brief ssd1306 fade blinking mode enumeration definition + */ +typedef enum +{ + SSD1306_FADE_BLINKING_MODE_DISABLE = 0x00, /**< disable fade blinking mode */ + SSD1306_FADE_BLINKING_MODE_FADE_OUT = 0x02, /**< fade out fade blinking mode */ + SSD1306_FADE_BLINKING_MODE_BLINKING = 0x03, /**< blinking fade blinking mode */ +} ssd1306_fade_blinking_mode_t; + +/** + * @brief ssd1306 scroll frame enumeration definition + */ +typedef enum +{ + SSD1306_SCROLL_FRAME_2 = 0x07, /**< scroll frame 2 */ + SSD1306_SCROLL_FRAME_3 = 0x04, /**< scroll frame 3 */ + SSD1306_SCROLL_FRAME_4 = 0x05, /**< scroll frame 4 */ + SSD1306_SCROLL_FRAME_5 = 0x00, /**< scroll frame 5 */ + SSD1306_SCROLL_FRAME_25 = 0x06, /**< scroll frame 25 */ + SSD1306_SCROLL_FRAME_64 = 0x01, /**< scroll frame 64 */ + SSD1306_SCROLL_FRAME_128 = 0x02, /**< scroll frame 128 */ + SSD1306_SCROLL_FRAME_256 = 0x03, /**< scroll frame 256 */ +} ssd1306_scroll_frame_t; + +/** + * @brief ssd1306 charge pump enumeration definition + */ +typedef enum +{ + SSD1306_CHARGE_PUMP_DISABLE = 0x00, /**< charge pump disable */ + SSD1306_CHARGE_PUMP_ENABLE = 0x01, /**< charge pump enable */ +} ssd1306_charge_pump_t; + +/** + * @brief ssd1306 segment column remap enumeration definition + */ +typedef enum +{ + SSD1306_SEGMENT_COLUMN_ADDRESS_0 = 0x00, /**< segment column remap address 0 */ + SSD1306_SEGMENT_COLUMN_ADDRESS_127 = 0x01, /**< segment column remap address 127 */ +} ssd1306_segment_column_remap_t; + +/** + * @brief ssd1306 entire display enumeration definition + */ +typedef enum +{ + SSD1306_ENTIRE_DISPLAY_OFF = 0x00, /**< entire display off */ + SSD1306_ENTIRE_DISPLAY_ON = 0x01, /**< entire display on */ +} ssd1306_entire_display_t; + +/** + * @brief ssd1306 display mode enumeration definition + */ +typedef enum +{ + SSD1306_DISPLAY_MODE_NORMAL = 0x00, /**< display mode normal */ + SSD1306_DISPLAY_MODE_INVERSE = 0x01, /**< display mode inverse */ +} ssd1306_display_mode_t; + +/** + * @brief ssd1306 display enumeration definition + */ +typedef enum +{ + SSD1306_DISPLAY_OFF = 0x00, /**< close display */ + SSD1306_DISPLAY_ON = 0x01, /**< open display */ +} ssd1306_display_t; + +/** + * @brief ssd1306 scan direction enumeration definition + */ +typedef enum +{ + SSD1306_SCAN_DIRECTION_COM0_START = 0x00, /**< scan direction com 0 start */ + SSD1306_SCAN_DIRECTION_COMN_1_START = 0x01, /**< scan direction com N-1 start */ +} ssd1306_scan_direction_t; + +/** + * @brief ssd1306 zoom in enumeration definition + */ +typedef enum +{ + SSD1306_ZOOM_IN_DISABLE = 0x00, /**< disable zoom in */ + SSD1306_ZOOM_IN_ENABLE = 0x01, /**< enable zoom in */ +} ssd1306_zoom_in_t; + +/** + * @brief ssd1306 pin conf enumeration definition + */ +typedef enum +{ + SSD1306_PIN_CONF_SEQUENTIAL = 0x00, /**< pin conf sequential */ + SSD1306_PIN_CONF_ALTERNATIVE = 0x01, /**< pin conf alternative */ +} ssd1306_pin_conf_t; + +/** + * @brief ssd1306 left right remap enumeration definition + */ +typedef enum +{ + SSD1306_LEFT_RIGHT_REMAP_DISABLE = 0x00, /**< disable left right remap */ + SSD1306_LEFT_RIGHT_REMAP_ENABLE = 0x01, /**< enable left right remap */ +} ssd1306_left_right_remap_t; + +/** + * @brief ssd1306 deselect level enumeration definition + */ +typedef enum +{ + SSD1306_DESELECT_LEVEL_0P65 = 0x00, /**< deselect level 0.65 */ + SSD1306_DESELECT_LEVEL_0P77 = 0x02, /**< deselect level 0.77 */ + SSD1306_DESELECT_LEVEL_0P83 = 0x03, /**< deselect level 0.83 */ +} ssd1306_deselect_level_t; + +/** + * @brief ssd1306 font enumeration definition + */ +typedef enum +{ + SSD1306_FONT_12 = 0x0C, /**< font 12 */ + SSD1306_FONT_16 = 0x10, /**< font 16 */ + SSD1306_FONT_24 = 0x18, /**< font 24 */ +} ssd1306_font_t; + +/** + * @brief ssd1306 handle structure definition + */ +typedef struct ssd1306_handle_s +{ + uint8_t (*iic_init)(void); /**< point to an iic_init function address */ + uint8_t (*iic_deinit)(void); /**< point to an iic_deinit function address */ + uint8_t (*iic_write)(uint8_t addr, uint8_t reg, uint8_t *buf, uint16_t len); /**< point to an iic_write function address */ + uint8_t (*spi_init)(void); /**< point to a spi_init function address */ + uint8_t (*spi_deinit)(void); /**< point to a spi_deinit function address */ + uint8_t (*spi_write_cmd)(uint8_t *buf, uint16_t len); /**< point to a spi_write_cmd function address */ + uint8_t (*spi_cmd_data_gpio_init)(void); /**< point to a spi_cmd_data_gpio_init function address */ + uint8_t (*spi_cmd_data_gpio_deinit)(void); /**< point to a spi_cmd_data_gpio_deinit function address */ + uint8_t (*spi_cmd_data_gpio_write)(uint8_t value); /**< point to a spi_cmd_data_gpio_write function address */ + uint8_t (*reset_gpio_init)(void); /**< point to a reset_gpio_init function address */ + uint8_t (*reset_gpio_deinit)(void); /**< point to a reset_gpio_deinit function address */ + uint8_t (*reset_gpio_write)(uint8_t value); /**< point to a reset_gpio_write function address */ + void (*debug_print)(const char *const fmt, ...); /**< point to a debug_print function address */ + void (*delay_ms)(uint32_t ms); /**< point to a delay_ms function address */ + uint8_t inited; /**< inited flag */ + uint8_t iic_addr; /**< iic address */ + uint8_t iic_spi; /**< iic spi type */ + uint8_t gram[128][8]; /**< gram buffer */ +} ssd1306_handle_t; + +/** + * @brief ssd1306 information structure definition + */ +typedef struct ssd1306_info_s +{ + char chip_name[32]; /**< chip name */ + char manufacturer_name[32]; /**< manufacturer name */ + char interface[8]; /**< chip interface name */ + float supply_voltage_min_v; /**< chip min supply voltage */ + float supply_voltage_max_v; /**< chip max supply voltage */ + float max_current_ma; /**< chip max current */ + float temperature_min; /**< chip min operating temperature */ + float temperature_max; /**< chip max operating temperature */ + uint32_t driver_version; /**< driver version */ +} ssd1306_info_t; + +/** + * @} + */ + +/** + * @defgroup ssd1306_link_driver ssd1306 link driver function + * @brief ssd1306 link driver modules + * @ingroup ssd1306_driver + * @{ + */ + +/** + * @brief initialize ssd1306_handle_t structure + * @param[in] HANDLE points to an ssd1306 handle structure + * @param[in] STRUCTURE is ssd1306_handle_t + * @note none + */ +#define DRIVER_SSD1306_LINK_INIT(HANDLE, STRUCTURE) memset(HANDLE, 0, sizeof(STRUCTURE)) + +/** + * @brief link iic_init function + * @param[in] HANDLE points to an ssd1306 handle structure + * @param[in] FUC points to an iic_init function address + * @note none + */ +#define DRIVER_SSD1306_LINK_IIC_INIT(HANDLE, FUC) (HANDLE)->iic_init = FUC + +/** + * @brief link iic_deinit function + * @param[in] HANDLE points to an ssd1306 handle structure + * @param[in] FUC points to an iic_deinit function address + * @note none + */ +#define DRIVER_SSD1306_LINK_IIC_DEINIT(HANDLE, FUC) (HANDLE)->iic_deinit = FUC + +/** + * @brief link iic_write function + * @param[in] HANDLE points to an ssd1306 handle structure + * @param[in] FUC points to an iic_write function address + * @note none + */ +#define DRIVER_SSD1306_LINK_IIC_WRITE(HANDLE, FUC) (HANDLE)->iic_write = FUC + +/** + * @brief link spi_init function + * @param[in] HANDLE points to an ssd1306 handle structure + * @param[in] FUC points to a spi_init function address + * @note none + */ +#define DRIVER_SSD1306_LINK_SPI_INIT(HANDLE, FUC) (HANDLE)->spi_init = FUC + +/** + * @brief link spi_deinit function + * @param[in] HANDLE points to an ssd1306 handle structure + * @param[in] FUC points to a spi_deinit function address + * @note none + */ +#define DRIVER_SSD1306_LINK_SPI_DEINIT(HANDLE, FUC) (HANDLE)->spi_deinit = FUC + +/** + * @brief link spi_write_cmd function + * @param[in] HANDLE points to an ssd1306 handle structure + * @param[in] FUC points to a spi_write_cmd function address + * @note none + */ +#define DRIVER_SSD1306_LINK_SPI_WRITE_COMMAND(HANDLE, FUC) (HANDLE)->spi_write_cmd = FUC + +/** + * @brief link spi_cmd_data_gpio_init function + * @param[in] HANDLE points to an ssd1306 handle structure + * @param[in] FUC points to a spi_cmd_data_gpio_init function address + * @note none + */ +#define DRIVER_SSD1306_LINK_SPI_COMMAND_DATA_GPIO_INIT(HANDLE, FUC) (HANDLE)->spi_cmd_data_gpio_init = FUC + +/** + * @brief link spi_cmd_data_gpio_deinit function + * @param[in] HANDLE points to an ssd1306 handle structure + * @param[in] FUC points to a spi_cmd_data_gpio_deinit function address + * @note none + */ +#define DRIVER_SSD1306_LINK_SPI_COMMAND_DATA_GPIO_DEINIT(HANDLE, FUC) (HANDLE)->spi_cmd_data_gpio_deinit = FUC + +/** + * @brief link spi_cmd_data_gpio_write function + * @param[in] HANDLE points to an ssd1306 handle structure + * @param[in] FUC points to a spi_cmd_data_gpio_write function address + * @note none + */ +#define DRIVER_SSD1306_LINK_SPI_COMMAND_DATA_GPIO_WRITE(HANDLE, FUC) (HANDLE)->spi_cmd_data_gpio_write = FUC + +/** + * @brief link reset_gpio_init function + * @param[in] HANDLE points to an ssd1306 handle structure + * @param[in] FUC points to a reset_gpio_init function address + * @note none + */ +#define DRIVER_SSD1306_LINK_RESET_GPIO_INIT(HANDLE, FUC) (HANDLE)->reset_gpio_init = FUC + +/** + * @brief link reset_gpio_deinit function + * @param[in] HANDLE points to an ssd1306 handle structure + * @param[in] FUC points to a reset_gpio_deinit function address + * @note none + */ +#define DRIVER_SSD1306_LINK_RESET_GPIO_DEINIT(HANDLE, FUC) (HANDLE)->reset_gpio_deinit = FUC + +/** + * @brief link reset_gpio_write function + * @param[in] HANDLE points to an ssd1306 handle structure + * @param[in] FUC points to a reset_gpio_write function address + * @note none + */ +#define DRIVER_SSD1306_LINK_RESET_GPIO_WRITE(HANDLE, FUC) (HANDLE)->reset_gpio_write = FUC + +/** + * @brief link delay_ms function + * @param[in] HANDLE points to an ssd1306 handle structure + * @param[in] FUC points to a delay_ms function address + * @note none + */ +#define DRIVER_SSD1306_LINK_DELAY_MS(HANDLE, FUC) (HANDLE)->delay_ms = FUC + +/** + * @brief link debug_print function + * @param[in] HANDLE points to an ssd1306 handle structure + * @param[in] FUC points to a debug_print function address + * @note none + */ +#define DRIVER_SSD1306_LINK_DEBUG_PRINT(HANDLE, FUC) (HANDLE)->debug_print = FUC + +/** + * @} + */ + +/** + * @defgroup ssd1306_base_driver ssd1306 base driver function + * @brief ssd1306 base driver modules + * @ingroup ssd1306_driver + * @{ + */ + +/** + * @brief get chip's information + * @param[out] *info points to an ssd1306 info structure + * @return status code + * - 0 success + * - 2 handle is NULL + * @note none + */ +uint8_t ssd1306_info(ssd1306_info_t *info); + +/** + * @brief set the chip interface + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] interface is the chip interface + * @return status code + * - 0 success + * - 2 handle is NULL + * @note none + */ +uint8_t ssd1306_set_interface(ssd1306_handle_t *handle, ssd1306_interface_t interface); + +/** + * @brief get the chip interface + * @param[in] *handle points to an ssd1306 handle structure + * @param[out] *interface points to a chip interface buffer + * @return status code + * - 0 success + * - 2 handle is NULL + * @note none + */ +uint8_t ssd1306_get_interface(ssd1306_handle_t *handle, ssd1306_interface_t *interface); + +/** + * @brief set the chip iic address + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] addr_pin is the iic address + * @return status code + * - 0 success + * - 2 handle is NULL + * @note none + */ +uint8_t ssd1306_set_addr_pin(ssd1306_handle_t *handle, ssd1306_address_t addr_pin); + +/** + * @brief get the chip iic address + * @param[in] *handle points to an ssd1306 handle structure + * @param[out] *addr_pin points to an iic address buffer + * @return status code + * - 0 success + * - 2 handle is NULL + * @note none + */ +uint8_t ssd1306_get_addr_pin(ssd1306_handle_t *handle, ssd1306_address_t *addr_pin); + +/** + * @brief initialize the chip + * @param[in] *handle points to an ssd1306 handle structure + * @return status code + * - 0 success + * - 1 iic or spi initialization failed + * - 2 handle is NULL + * - 3 linked functions is NULL + * - 4 reset failed + * - 5 command && data init failed + * - 6 interface param is invalid + * @note none + */ +uint8_t ssd1306_init(ssd1306_handle_t *handle); + +/** + * @brief close the chip + * @param[in] *handle points to an ssd1306 handle structure + * @return status code + * - 0 success + * - 1 iic or spi deinit failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 power down failed + * - 5 reset gpio deinit failed + * - 6 command && data deinit failed + * - 7 interface param is invalid + * @note none + */ +uint8_t ssd1306_deinit(ssd1306_handle_t *handle); + +/** + * @brief clear the screen + * @param[in] *handle points to an ssd1306 handle structure + * @return status code + * - 0 success + * - 1 clear failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_clear(ssd1306_handle_t *handle); + +/** + * @brief update the gram data + * @param[in] *handle points to an ssd1306 handle structure + * @return status code + * - 0 success + * - 1 gram update failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_gram_update(ssd1306_handle_t *handle); + +/** + * @brief write a point + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] x is the coordinate x + * @param[in] y is the coordinate y + * @param[in] data is the write data + * @return status code + * - 0 success + * - 1 write point failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 x or y is invalid + * @note none + */ +uint8_t ssd1306_write_point(ssd1306_handle_t *handle, uint8_t x, uint8_t y, uint8_t data); + +/** + * @brief read a point + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] x is the coordinate x + * @param[in] y is the coordinate y + * @param[out] *data points to a data buffer + * @return status code + * - 0 success + * - 1 read point failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 x or y is invalid + * @note none + */ +uint8_t ssd1306_read_point(ssd1306_handle_t *handle, uint8_t x, uint8_t y, uint8_t *data); + +/** + * @brief write a point in the gram + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] x is the coordinate x + * @param[in] y is the coordinate y + * @param[in] data is the write data + * @return status code + * - 0 success + * - 1 gram write point failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 x or y is invalid + * @note none + */ +uint8_t ssd1306_gram_write_point(ssd1306_handle_t *handle, uint8_t x, uint8_t y, uint8_t data); + +/** + * @brief read a point from the gram + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] x is the coordinate x + * @param[in] y is the coordinate y + * @param[out] *data points to a data buffer + * @return status code + * - 0 success + * - 1 gram read point failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 x or y is invalid + * @note none + */ +uint8_t ssd1306_gram_read_point(ssd1306_handle_t *handle, uint8_t x, uint8_t y, uint8_t *data); + +/** + * @brief draw a string in the gram + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] x is the coordinate x + * @param[in] y is the coordinate y + * @param[in] *str points to a write string address + * @param[in] len is the length of the string + * @param[in] color is the display color + * @param[in] font is the display font size + * @return status code + * - 0 success + * - 1 gram write string failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 x or y is invalid + * @note none + */ +uint8_t ssd1306_gram_write_string(ssd1306_handle_t *handle, uint8_t x, uint8_t y, char *str, uint16_t len, uint8_t color, ssd1306_font_t font); + +/** + * @brief fill a rectangle in the gram + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] left is the left coordinate x + * @param[in] top is the top coordinate y + * @param[in] right is the right coordinate x + * @param[in] bottom is the bottom coordinate y + * @param[in] color is the display color + * @return status code + * - 0 success + * - 1 gram fill rect failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 left or top is invalid + * - 5 right or bottom is invalid + * - 6 left > right or top > bottom + * @note none + */ +uint8_t ssd1306_gram_fill_rect(ssd1306_handle_t *handle, uint8_t left, uint8_t top, uint8_t right, uint8_t bottom, uint8_t color); + +/** + * @brief draw a picture in the gram + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] left is the left coordinate x + * @param[in] top is the top coordinate y + * @param[in] right is the right coordinate x + * @param[in] bottom is the bottom coordinate y + * @param[in] *img points to an image buffer + * @return status code + * - 0 success + * - 1 gram draw picture failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 left or top is invalid + * - 5 right or bottom is invalid + * - 6 left > right or top > bottom + * @note none + */ +uint8_t ssd1306_gram_draw_picture(ssd1306_handle_t *handle, uint8_t left, uint8_t top, uint8_t right, uint8_t bottom, uint8_t *img); + +/** + * @brief set the low column start address + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] addr is the low column start address + * @return status code + * - 0 success + * - 1 set low column start address failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 addr is invalid + * @note addr <= 0xF + */ +uint8_t ssd1306_set_low_column_start_address(ssd1306_handle_t *handle, uint8_t addr); + +/** + * @brief set the high column start address + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] addr is the high column start address + * @return status code + * - 0 success + * - 1 set high column start address failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 addr is invalid + * @note addr <= 0xF + */ +uint8_t ssd1306_set_high_column_start_address(ssd1306_handle_t *handle, uint8_t addr); + +/** + * @brief set the memory addressing mode + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] mode is the memory addressing mode + * @return status code + * - 0 success + * - 1 set memory addressing mode failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_memory_addressing_mode(ssd1306_handle_t *handle, ssd1306_memory_addressing_mode_t mode); + +/** + * @brief set the column address range + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] start_addr is the column start address + * @param[in] end_addr is the column end address + * @return status code + * - 0 success + * - 1 set column address range failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 start addr is invalid + * - 5 end addr is invalid + * @note start addr and end addr can't be over 0x7F + */ +uint8_t ssd1306_set_column_address_range(ssd1306_handle_t *handle, uint8_t start_addr, uint8_t end_addr); + +/** + * @brief set the page address range + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] start_addr is the page start address + * @param[in] end_addr is the page end address + * @return status code + * - 0 success + * - 1 set page address range failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 start addr is invalid + * - 5 end addr is invalid + * @note start addr and end addr can't be over 0x07 + */ +uint8_t ssd1306_set_page_address_range(ssd1306_handle_t *handle, uint8_t start_addr, uint8_t end_addr); + +/** + * @brief set the fade blinking mode + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] mode is the fade blinking mode + * @param[in] frames is the fade or blinking frames + * @return status code + * - 0 success + * - 1 set fade blinking mode failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 frames is invalid + * @note frames max is 0x0F and div is (frames + 1) * 8 + */ +uint8_t ssd1306_set_fade_blinking_mode(ssd1306_handle_t *handle, ssd1306_fade_blinking_mode_t mode, uint8_t frames); + +/** + * @brief set the right horizontal scroll + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] start_page_addr is the start page address + * @param[in] end_page_addr is the end page address + * @param[in] frames is the scroll frames + * @return status code + * - 0 success + * - 1 set right horizontal scroll failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 start page addr is invalid + * - 5 end page addr is invalid + * @note start_page_addr <= 0x07, end_page_addr <= 0x07 + */ +uint8_t ssd1306_set_right_horizontal_scroll(ssd1306_handle_t *handle, uint8_t start_page_addr, uint8_t end_page_addr, + ssd1306_scroll_frame_t frames); + +/** + * @brief set the left horizontal scroll + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] start_page_addr is the start page address + * @param[in] end_page_addr is the end page address + * @param[in] frames is the scroll frames + * @return status code + * - 0 success + * - 1 set left horizontal scroll failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 start_page_addr is invalid + * - 5 end_page_addr is invalid + * @note start_page_addr <= 0x07, end_page_addr <= 0x07 + */ +uint8_t ssd1306_set_left_horizontal_scroll(ssd1306_handle_t *handle, uint8_t start_page_addr, uint8_t end_page_addr, + ssd1306_scroll_frame_t frames); + +/** + * @brief set the vertical right horizontal scroll + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] start_page_addr is the start page address + * @param[in] end_page_addr is the end page address + * @param[in] rows is the row address + * @param[in] frames is the scroll frames + * @return status code + * - 0 success + * - 1 set vertical right horizontal scroll failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 start_page_addr is invalid + * - 5 end_page_addr is invalid + * - 6 rows is invalid + * @note start_page_addr <= 0x07, end_page_addr <= 0x07, rows <= 0x3F + */ +uint8_t ssd1306_set_vertical_right_horizontal_scroll(ssd1306_handle_t *handle, uint8_t start_page_addr, uint8_t end_page_addr, + uint8_t rows, ssd1306_scroll_frame_t frames); + +/** + * @brief set the vertical left horizontal scroll + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] start_page_addr is the start page address + * @param[in] end_page_addr is the end page address + * @param[in] rows is the row address + * @param[in] frames is the scroll frames + * @return status code + * - 0 success + * - 1 set vertical left horizontal scroll failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 start_page_addr is invalid + * - 5 end_page_addr is invalid + * - 6 rows is invalid + * @note start_page_addr <= 0x07, end_page_addr <= 0x07, rows <= 0x3F + */ +uint8_t ssd1306_set_vertical_left_horizontal_scroll(ssd1306_handle_t *handle, uint8_t start_page_addr, uint8_t end_page_addr, + uint8_t rows, ssd1306_scroll_frame_t frames); + +/** + * @brief deactivate the scroll + * @param[in] *handle points to an ssd1306 handle structure + * @return status code + * - 0 success + * - 1 deactivate scroll failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_deactivate_scroll(ssd1306_handle_t *handle); + +/** + * @brief activate the scroll + * @param[in] *handle points to an ssd1306 handle structure + * @return status code + * - 0 success + * - 1 activate scroll failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_activate_scroll(ssd1306_handle_t *handle); + +/** + * @brief set the display start line + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] l is the start line + * @return status code + * - 0 success + * - 1 set display start line failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 line is invalid + * @note line <= 0x3F + */ +uint8_t ssd1306_set_display_start_line(ssd1306_handle_t *handle, uint8_t l); + +/** + * @brief set the display contrast + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] contrast is the display contrast + * @return status code + * - 0 success + * - 1 set contrast failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_contrast(ssd1306_handle_t *handle, uint8_t contrast); + +/** + * @brief enable or disable the charge pump + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] enable is a bool value + * @return status code + * - 0 success + * - 1 set charge pump failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_charge_pump(ssd1306_handle_t *handle, ssd1306_charge_pump_t enable); + +/** + * @brief set the segment remap + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] remap is the segment remap param + * @return status code + * - 0 success + * - 1 set segment remap failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_segment_remap(ssd1306_handle_t *handle, ssd1306_segment_column_remap_t remap); + +/** + * @brief set the vertical scroll area + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] start_row is the start row + * @param[in] end_row is the end row + * @return status code + * - 0 success + * - 1 set vertical scroll area failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 start_row is invalid + * - 5 end_row is invalid + * - 6 end_row > start_row + * @note start_row <= 0x3F, end_row <= 0x7F, start_row >= end_row + */ +uint8_t ssd1306_set_vertical_scroll_area(ssd1306_handle_t *handle, uint8_t start_row, uint8_t end_row); + +/** + * @brief enable or disable the entire display + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] enable is a bool value + * @return status code + * - 0 success + * - 1 set entire display failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_entire_display(ssd1306_handle_t *handle, ssd1306_entire_display_t enable); + +/** + * @brief set the display mode + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] mode is the display mode + * @return status code + * - 0 success + * - 1 set display mode failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_display_mode(ssd1306_handle_t *handle, ssd1306_display_mode_t mode); + +/** + * @brief set the multiplex ratio + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] multiplex is the multiplex ratio + * @return status code + * - 0 success + * - 1 set multiplex ratio failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 multiplex is too small + * - 5 multiplex is too large + * @note multiplex must be over 0x0E and less than 0x40 + */ +uint8_t ssd1306_set_multiplex_ratio(ssd1306_handle_t *handle, uint8_t multiplex); + +/** + * @brief enable or disable the display + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] on_off is a bool value + * @return status code + * - 0 success + * - 1 set display failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_display(ssd1306_handle_t *handle, ssd1306_display_t on_off); + +/** + * @brief set the page address + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] addr is the page address + * @return status code + * - 0 success + * - 1 set page address failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 addr is invalid + * @note addr <= 0x07 + */ +uint8_t ssd1306_set_page_address(ssd1306_handle_t *handle, uint8_t addr); + +/** + * @brief set the scan direction + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] dir is the scan direction + * @return status code + * - 0 success + * - 1 set scan direction failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_scan_direction(ssd1306_handle_t *handle, ssd1306_scan_direction_t dir); + +/** + * @brief set the display offset + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] offset is the display offset + * @return status code + * - 0 success + * - 1 set display offset failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 offset is invalid + * @note offset <= 0x3F + */ +uint8_t ssd1306_set_display_offset(ssd1306_handle_t *handle, uint8_t offset); + +/** + * @brief set the display clock + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] oscillator_frequency is the oscillator frequency + * @param[in] clock_divide is the clock divide + * @return status code + * - 0 success + * - 1 set display clock failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 oscillator frequency is invalid + * - 5 clock divide is invalid + * @note oscillator_frequency <= 0x0F, clock_divide <= 0x0F + */ +uint8_t ssd1306_set_display_clock(ssd1306_handle_t *handle, uint8_t oscillator_frequency, uint8_t clock_divide); + +/** + * @brief set the display zoom in + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] zoom is the display zoom in + * @return status code + * - 0 success + * - 1 set zoom in failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_zoom_in(ssd1306_handle_t *handle, ssd1306_zoom_in_t zoom); + +/** + * @brief set the pre charge period + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] phase1_period is the phase1 period + * @param[in] phase2_period is the phase2 period + * @return status code + * - 0 success + * - 1 set pre charge period failed + * - 2 handle is NULL + * - 3 handle is not initialized + * - 4 phase1 period is invalid + * - 5 phase2 period is invalid + * @note phase1_period <= 0x0F, phase2_period <= 0x0F + */ +uint8_t ssd1306_set_precharge_period(ssd1306_handle_t *handle, uint8_t phase1_period, uint8_t phase2_period); + +/** + * @brief set the hardware com pins + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] conf is the pin conf + * @param[in] remap is the left right remap + * @return status code + * - 0 success + * - 1 set com pins hardware conf failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_com_pins_hardware_conf(ssd1306_handle_t *handle, ssd1306_pin_conf_t conf, ssd1306_left_right_remap_t remap); + +/** + * @brief set the deselect level + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] level is the deselect level + * @return status code + * - 0 success + * - 1 set deselect level failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_set_deselect_level(ssd1306_handle_t *handle, ssd1306_deselect_level_t level); + +/** + * @} + */ + +/** + * @defgroup ssd1306_extend_driver ssd1306 extend driver function + * @brief ssd1306 extend driver modules + * @ingroup ssd1306_driver + * @{ + */ + +/** + * @brief write the register command + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] *buf points to a data buffer + * @param[in] len is the data length + * @return status code + * - 0 success + * - 1 write failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_write_cmd(ssd1306_handle_t *handle, uint8_t *buf, uint8_t len); + +/** + * @brief write the register data + * @param[in] *handle points to an ssd1306 handle structure + * @param[in] *buf points to a data buffer + * @param[in] len is the data length + * @return status code + * - 0 success + * - 1 write failed + * - 2 handle is NULL + * - 3 handle is not initialized + * @note none + */ +uint8_t ssd1306_write_data(ssd1306_handle_t *handle, uint8_t *buf, uint8_t len); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/src/basic/ssd1306/driver_ssd1306_basic.c b/app/src/basic/ssd1306/driver_ssd1306_basic.c new file mode 100644 index 0000000..79806e7 --- /dev/null +++ b/app/src/basic/ssd1306/driver_ssd1306_basic.c @@ -0,0 +1,577 @@ +/** + * Copyright (c) 2015 - present LibDriver All rights reserved + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * @file driver_ssd1306_basic.c + * @brief driver ssd1306 basic source file + * @version 2.0.0 + * @author Shifeng Li + * @date 2021-03-30 + * + *

history

+ * + *
Date Version Author Description + *
2021/03/30 2.0 Shifeng Li format the code + *
2020/12/10 1.0 Shifeng Li first upload + *
+ */ + +#include "driver_ssd1306_basic.h" + +static ssd1306_handle_t gs_handle; /**< ssd1306 handle */ + +/** + * @brief basic example init + * @param[in] interface is the interface type + * @param[in] addr is the iic device address + * @return status code + * - 0 success + * - 1 init failed + * @note none + */ +uint8_t ssd1306_basic_init(ssd1306_interface_t interface, ssd1306_address_t addr) +{ + uint8_t res; + + /* link functions */ + DRIVER_SSD1306_LINK_INIT(&gs_handle, ssd1306_handle_t); + DRIVER_SSD1306_LINK_IIC_INIT(&gs_handle, ssd1306_interface_iic_init); + DRIVER_SSD1306_LINK_IIC_DEINIT(&gs_handle, ssd1306_interface_iic_deinit); + DRIVER_SSD1306_LINK_IIC_WRITE(&gs_handle, ssd1306_interface_iic_write); + DRIVER_SSD1306_LINK_SPI_INIT(&gs_handle, ssd1306_interface_spi_init); + DRIVER_SSD1306_LINK_SPI_DEINIT(&gs_handle, ssd1306_interface_spi_deinit); + DRIVER_SSD1306_LINK_SPI_WRITE_COMMAND(&gs_handle, ssd1306_interface_spi_write_cmd); + DRIVER_SSD1306_LINK_SPI_COMMAND_DATA_GPIO_INIT(&gs_handle, ssd1306_interface_spi_cmd_data_gpio_init); + DRIVER_SSD1306_LINK_SPI_COMMAND_DATA_GPIO_DEINIT(&gs_handle, ssd1306_interface_spi_cmd_data_gpio_deinit); + DRIVER_SSD1306_LINK_SPI_COMMAND_DATA_GPIO_WRITE(&gs_handle, ssd1306_interface_spi_cmd_data_gpio_write); + DRIVER_SSD1306_LINK_RESET_GPIO_INIT(&gs_handle, ssd1306_interface_reset_gpio_init); + DRIVER_SSD1306_LINK_RESET_GPIO_DEINIT(&gs_handle, ssd1306_interface_reset_gpio_deinit); + DRIVER_SSD1306_LINK_RESET_GPIO_WRITE(&gs_handle, ssd1306_interface_reset_gpio_write); + DRIVER_SSD1306_LINK_DELAY_MS(&gs_handle, ssd1306_interface_delay_ms); + DRIVER_SSD1306_LINK_DEBUG_PRINT(&gs_handle, ssd1306_interface_debug_print); + + /* set interface */ + res = ssd1306_set_interface(&gs_handle, interface); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set interface failed.\n"); + + return 1; + } + + /* set addr pin */ + res = ssd1306_set_addr_pin(&gs_handle, addr); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set addr failed.\n"); + + return 1; + } + + /* ssd1306 init */ + res = ssd1306_init(&gs_handle); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: init failed.\n"); + + return 1; + } + + /* close display */ + res = ssd1306_set_display(&gs_handle, SSD1306_DISPLAY_OFF); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set display failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* set column address range */ + res = ssd1306_set_column_address_range(&gs_handle, SSD1306_BASIC_DEFAULT_COLUMN_ADDRESS_RANGE_START, SSD1306_BASIC_DEFAULT_COLUMN_ADDRESS_RANGE_END); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set column address range failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* set page address range */ + res = ssd1306_set_page_address_range(&gs_handle, SSD1306_BASIC_DEFAULT_PAGE_ADDRESS_RANGE_START, SSD1306_BASIC_DEFAULT_PAGE_ADDRESS_RANGE_END); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set page address range failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* set low column start address */ + res = ssd1306_set_low_column_start_address(&gs_handle, SSD1306_BASIC_DEFAULT_LOW_COLUMN_START_ADDRESS); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set low column start address failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* set high column start address */ + res = ssd1306_set_high_column_start_address(&gs_handle, SSD1306_BASIC_DEFAULT_HIGH_COLUMN_START_ADDRESS); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set high column start address failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* set display start line */ + res = ssd1306_set_display_start_line(&gs_handle, SSD1306_BASIC_DEFAULT_DISPLAY_START_LINE); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set display start line failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* set fade blinking mode */ + res = ssd1306_set_fade_blinking_mode(&gs_handle, SSD1306_BASIC_DEFAULT_FADE_BLINKING_MODE, SSD1306_BASIC_DEFAULT_FADE_FRAMES); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set fade blinking failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* deactivate scroll */ + res = ssd1306_deactivate_scroll(&gs_handle); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set deactivate scroll failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* set zoom in */ + res = ssd1306_set_zoom_in(&gs_handle, SSD1306_BASIC_DEFAULT_ZOOM_IN); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set set zoom in failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* set contrast */ + res = ssd1306_set_contrast(&gs_handle, SSD1306_BASIC_DEFAULT_CONTRAST); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set contrast failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* set segment remap */ + res = ssd1306_set_segment_remap(&gs_handle, SSD1306_BASIC_DEFAULT_SEGMENT); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set segment remap failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* set scan direction */ + res = ssd1306_set_scan_direction(&gs_handle, SSD1306_BASIC_DEFAULT_SCAN_DIRECTION); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set scan direction failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* set display mode */ + res = ssd1306_set_display_mode(&gs_handle, SSD1306_BASIC_DEFAULT_DISPLAY_MODE); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set display mode failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* set multiplex ratio */ + res = ssd1306_set_multiplex_ratio(&gs_handle, SSD1306_BASIC_DEFAULT_MULTIPLEX_RATIO); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set multiplex ratio failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* set display offset */ + res = ssd1306_set_display_offset(&gs_handle, SSD1306_BASIC_DEFAULT_DISPLAY_OFFSET); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set display offset failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* set display clock */ + res = ssd1306_set_display_clock(&gs_handle, SSD1306_BASIC_DEFAULT_OSCILLATOR_FREQUENCY, SSD1306_BASIC_DEFAULT_CLOCK_DIVIDE); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set display clock failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* set pre charge period */ + res = ssd1306_set_precharge_period(&gs_handle, SSD1306_BASIC_DEFAULT_PHASE1_PERIOD, SSD1306_BASIC_DEFAULT_PHASE2_PERIOD); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set pre charge period failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* set hardware pins conf */ + res = ssd1306_set_com_pins_hardware_conf(&gs_handle, SSD1306_BASIC_DEFAULT_PIN_CONF, SSD1306_BASIC_DEFAULT_LEFT_RIGHT_REMAP); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set com pins hardware conf failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* set deselect level 0.77 */ + res = ssd1306_set_deselect_level(&gs_handle, SSD1306_BASIC_DEFAULT_DESELECT_LEVEL); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set deselect level failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* set page memory addressing mode */ + res = ssd1306_set_memory_addressing_mode(&gs_handle, SSD1306_MEMORY_ADDRESSING_MODE_PAGE); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set memory addressing level failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* enable charge pump */ + res = ssd1306_set_charge_pump(&gs_handle, SSD1306_CHARGE_PUMP_ENABLE); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set charge pump failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* entire display off */ + res = ssd1306_set_entire_display(&gs_handle, SSD1306_ENTIRE_DISPLAY_OFF); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set entire display failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* enable display */ + res = ssd1306_set_display(&gs_handle, SSD1306_DISPLAY_ON); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: set display failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + /* clear screen */ + res = ssd1306_clear(&gs_handle); + if (res != 0) + { + ssd1306_interface_debug_print("ssd1306: clear failed.\n"); + (void)ssd1306_deinit(&gs_handle); + + return 1; + } + + return 0; +} + +/** + * @brief basic example deinit + * @return status code + * - 0 success + * - 1 deinit failed + * @note none + */ +uint8_t ssd1306_basic_deinit(void) +{ + /* deinit ssd1306 */ + if (ssd1306_deinit(&gs_handle) != 0) + { + return 1; + } + else + { + return 0; + } +} + +/** + * @brief basic example display on + * @return status code + * - 0 success + * - 1 display on failed + * @note none + */ +uint8_t ssd1306_basic_display_on(void) +{ + uint8_t res; + + /* display on */ + res = ssd1306_set_display(&gs_handle, SSD1306_DISPLAY_ON); + if (res != 0) + { + return 1; + } + else + { + return 0; + } +} + +/** + * @brief basic example display off + * @return status code + * - 0 success + * - 1 display off failed + * @note none + */ +uint8_t ssd1306_basic_display_off(void) +{ + uint8_t res; + + /* display off */ + res = ssd1306_set_display(&gs_handle, SSD1306_DISPLAY_OFF); + if (res != 0) + { + return 1; + } + else + { + return 0; + } +} + +/** + * @brief basic example clear + * @return status code + * - 0 success + * - 1 clear failed + * @note none + */ +uint8_t ssd1306_basic_clear(void) +{ + /* clear */ + if (ssd1306_clear(&gs_handle) != 0) + { + return 1; + } + else + { + return 0; + } +} + +/** + * @brief basic example write a point + * @param[in] x is the coordinate x + * @param[in] y is the coordinate y + * @param[in] data is the written data + * @return status code + * - 0 success + * - 1 write point failed + * @note none + */ +uint8_t ssd1306_basic_write_point(uint8_t x, uint8_t y, uint8_t data) +{ + uint8_t res; + + /* write point */ + res = ssd1306_write_point(&gs_handle, x, y, data); + if (res != 0) + { + return 1; + } + + return 0; +} + +/** + * @brief basic example read a point + * @param[in] x is the coordinate x + * @param[in] y is the coordinate y + * @param[out] *data points to a data buffer + * @return status code + * - 0 success + * - 1 read point failed + * @note none + */ +uint8_t ssd1306_basic_read_point(uint8_t x, uint8_t y, uint8_t *data) +{ + uint8_t res; + + /* read point in gram */ + res = ssd1306_read_point(&gs_handle, x, y, data); + if (res != 0) + { + return 1; + } + + return 0; +} + +/** + * @brief basic example draw a string + * @param[in] x is the coordinate x + * @param[in] y is the coordinate y + * @param[in] *str points to a written string address + * @param[in] len is the length of the string + * @param[in] color is the display color + * @param[in] font is the display font size + * @return status code + * - 0 success + * - 1 write string failed + * @note none + */ +uint8_t ssd1306_basic_string(uint8_t x, uint8_t y, char *str, uint16_t len, uint8_t color, ssd1306_font_t font) +{ + uint8_t res; + + /* write string in gram */ + res = ssd1306_gram_write_string(&gs_handle, x, y, str, len, color, font); + if (res != 0) + { + return 1; + } + + /* update gram */ + if (ssd1306_gram_update(&gs_handle) != 0) + { + return 1; + } + else + { + return 0; + } +} + +/** + * @brief basic example fill a rectangle + * @param[in] left is the left coordinate x + * @param[in] top is the top coordinate y + * @param[in] right is the right coordinate x + * @param[in] bottom is the bottom coordinate y + * @param[in] color is the display color + * @return status code + * - 0 success + * - 1 fill rect failed + * @note none + */ +uint8_t ssd1306_basic_rect(uint8_t left, uint8_t top, uint8_t right, uint8_t bottom, uint8_t color) +{ + uint8_t res; + + /* fill rect in gram */ + res = ssd1306_gram_fill_rect(&gs_handle, left, top, right, bottom, color); + if (res != 0) + { + return 1; + } + + /* update gram */ + if (ssd1306_gram_update(&gs_handle) != 0) + { + return 1; + } + else + { + return 0; + } +} + +/** + * @brief basic example draw a picture + * @param[in] left is the left coordinate x + * @param[in] top is the top coordinate y + * @param[in] right is the right coordinate x + * @param[in] bottom is the bottom coordinate y + * @param[in] *img points to a image buffer + * @return status code + * - 0 success + * - 1 draw picture failed + * @note none + */ +uint8_t ssd1306_basic_picture(uint8_t left, uint8_t top, uint8_t right, uint8_t bottom, uint8_t *img) +{ + uint8_t res; + + /* draw picture in gram */ + res = ssd1306_gram_draw_picture(&gs_handle, left, top, right, bottom, img); + if (res != 0) + { + return 1; + } + + /* update gram */ + if (ssd1306_gram_update(&gs_handle) != 0) + { + return 1; + } + else + { + return 0; + } +} diff --git a/app/src/basic/ssd1306/driver_ssd1306_basic.h b/app/src/basic/ssd1306/driver_ssd1306_basic.h new file mode 100644 index 0000000..0480830 --- /dev/null +++ b/app/src/basic/ssd1306/driver_ssd1306_basic.h @@ -0,0 +1,203 @@ +/** + * Copyright (c) 2015 - present LibDriver All rights reserved + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * @file driver_ssd1306_basic.h + * @brief driver ssd1306 basic header file + * @version 2.0.0 + * @author Shifeng Li + * @date 2021-03-30 + * + *

history

+ * + *
Date Version Author Description + *
2021/03/30 2.0 Shifeng Li format the code + *
2020/12/10 1.0 Shifeng Li first upload + *
+ */ + +#ifndef DRIVER_SSD1306_BASIC_H +#define DRIVER_SSD1306_BASIC_H + +#include "driver_ssd1306_interface.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +/** + * @defgroup ssd1306_example_driver ssd1306 example driver function + * @brief ssd1306 example driver modules + * @ingroup ssd1306_driver + * @{ + */ + +/** + * @brief ssd1306 basic example default definition + */ +#define SSD1306_BASIC_DEFAULT_DESELECT_LEVEL SSD1306_DESELECT_LEVEL_0P77 /**< set deselect level 0.77 */ +#define SSD1306_BASIC_DEFAULT_LEFT_RIGHT_REMAP SSD1306_LEFT_RIGHT_REMAP_DISABLE /**< disable remap */ +#define SSD1306_BASIC_DEFAULT_PIN_CONF SSD1306_PIN_CONF_ALTERNATIVE /**< set alternative */ +#define SSD1306_BASIC_DEFAULT_PHASE1_PERIOD 0x01 /**< set phase 1 */ +#define SSD1306_BASIC_DEFAULT_PHASE2_PERIOD 0x0F /**< set phase F */ +#define SSD1306_BASIC_DEFAULT_OSCILLATOR_FREQUENCY 0x08 /**< set 8 */ +#define SSD1306_BASIC_DEFAULT_CLOCK_DIVIDE 0x00 /**< set clock div 0 */ +#define SSD1306_BASIC_DEFAULT_DISPLAY_OFFSET 0x00 /**< set display offset */ +#define SSD1306_BASIC_DEFAULT_MULTIPLEX_RATIO 0x3F /**< set ratio */ +#define SSD1306_BASIC_DEFAULT_DISPLAY_MODE SSD1306_DISPLAY_MODE_NORMAL /**< set normal mode */ +#define SSD1306_BASIC_DEFAULT_SCAN_DIRECTION SSD1306_SCAN_DIRECTION_COMN_1_START /**< set scan 1 */ +#define SSD1306_BASIC_DEFAULT_SEGMENT SSD1306_SEGMENT_COLUMN_ADDRESS_127 /**< set column 127 */ +#define SSD1306_BASIC_DEFAULT_CONTRAST 0xCF /**< set contrast CF */ +#define SSD1306_BASIC_DEFAULT_ZOOM_IN SSD1306_ZOOM_IN_DISABLE /**< disable zoom in */ +#define SSD1306_BASIC_DEFAULT_FADE_BLINKING_MODE SSD1306_FADE_BLINKING_MODE_DISABLE /**< disable fade */ +#define SSD1306_BASIC_DEFAULT_FADE_FRAMES 0x00 /**< set frame 0 */ +#define SSD1306_BASIC_DEFAULT_DISPLAY_START_LINE 0x00 /**< set start line 0 */ +#define SSD1306_BASIC_DEFAULT_HIGH_COLUMN_START_ADDRESS 0x00 /**< set high start 0 */ +#define SSD1306_BASIC_DEFAULT_LOW_COLUMN_START_ADDRESS 0x00 /**< set low start 0 */ +#define SSD1306_BASIC_DEFAULT_PAGE_ADDRESS_RANGE_START 0x00 /**< set page range start */ +#define SSD1306_BASIC_DEFAULT_PAGE_ADDRESS_RANGE_END 0x07 /**< set page range end */ +#define SSD1306_BASIC_DEFAULT_COLUMN_ADDRESS_RANGE_START 0x00 /**< set range start */ +#define SSD1306_BASIC_DEFAULT_COLUMN_ADDRESS_RANGE_END 0x7F /**< set range end */ + +/** + * @brief basic example init + * @param[in] interface is the interface type + * @param[in] addr is the iic device address + * @return status code + * - 0 success + * - 1 init failed + * @note none + */ +uint8_t ssd1306_basic_init(ssd1306_interface_t interface, ssd1306_address_t addr); + +/** + * @brief basic example deinit + * @return status code + * - 0 success + * - 1 deinit failed + * @note none + */ +uint8_t ssd1306_basic_deinit(void); + +/** + * @brief basic example display on + * @return status code + * - 0 success + * - 1 display on failed + * @note none + */ +uint8_t ssd1306_basic_display_on(void); + +/** + * @brief basic example display off + * @return status code + * - 0 success + * - 1 display off failed + * @note none + */ +uint8_t ssd1306_basic_display_off(void); + +/** + * @brief basic example clear + * @return status code + * - 0 success + * - 1 clear failed + * @note none + */ +uint8_t ssd1306_basic_clear(void); + +/** + * @brief basic example write a point + * @param[in] x is the coordinate x + * @param[in] y is the coordinate y + * @param[in] data is the written data + * @return status code + * - 0 success + * - 1 write point failed + * @note none + */ +uint8_t ssd1306_basic_write_point(uint8_t x, uint8_t y, uint8_t data); + +/** + * @brief basic example read a point + * @param[in] x is the coordinate x + * @param[in] y is the coordinate y + * @param[out] *data points to a data buffer + * @return status code + * - 0 success + * - 1 read point failed + * @note none + */ +uint8_t ssd1306_basic_read_point(uint8_t x, uint8_t y, uint8_t *data); + +/** + * @brief basic example draw a string + * @param[in] x is the coordinate x + * @param[in] y is the coordinate y + * @param[in] *str points to a written string address + * @param[in] len is the length of the string + * @param[in] color is the display color + * @param[in] font is the display font size + * @return status code + * - 0 success + * - 1 write string failed + * @note none + */ +uint8_t ssd1306_basic_string(uint8_t x, uint8_t y, char *str, uint16_t len, uint8_t color, ssd1306_font_t font); + +/** + * @brief basic example fill a rectangle + * @param[in] left is the left coordinate x + * @param[in] top is the top coordinate y + * @param[in] right is the right coordinate x + * @param[in] bottom is the bottom coordinate y + * @param[in] color is the display color + * @return status code + * - 0 success + * - 1 fill rect failed + * @note none + */ +uint8_t ssd1306_basic_rect(uint8_t left, uint8_t top, uint8_t right, uint8_t bottom, uint8_t color); + +/** + * @brief basic example draw a picture + * @param[in] left is the left coordinate x + * @param[in] top is the top coordinate y + * @param[in] right is the right coordinate x + * @param[in] bottom is the bottom coordinate y + * @param[in] *img points to a image buffer + * @return status code + * - 0 success + * - 1 draw picture failed + * @note none + */ +uint8_t ssd1306_basic_picture(uint8_t left, uint8_t top, uint8_t right, uint8_t bottom, uint8_t *img); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/src/basic/ssd1306/driver_ssd1306_font.h b/app/src/basic/ssd1306/driver_ssd1306_font.h new file mode 100644 index 0000000..1734127 --- /dev/null +++ b/app/src/basic/ssd1306/driver_ssd1306_font.h @@ -0,0 +1,350 @@ +/** + * Copyright (c) 2015 - present LibDriver All rights reserved + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * @file driver_ssd1306_font.h + * @brief driver ssd1306 font header file + * @version 2.0.0 + * @author Shifeng Li + * @date 2021-03-30 + * + *

history

+ * + *
Date Version Author Description + *
2021/03/30 2.0 Shifeng Li format the code + *
2020/12/10 1.0 Shifeng Li first upload + *
+ */ + +#ifndef DRIVER_SSD1306_FONT_H +#define DRIVER_SSD1306_FONT_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +static const uint8_t gsc_ssd1306_ascii_1206[95][12] = +{ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*" ", 0*/ + {0x00, 0x00, 0x00, 0x00, 0x3F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"!", 1*/ + {0x00, 0x00, 0x30, 0x00, 0x40, 0x00, 0x30, 0x00, 0x40, 0x00, 0x00, 0x00}, /*""", 2*/ + {0x09, 0x00, 0x0B, 0xC0, 0x3D, 0x00, 0x0B, 0xC0, 0x3D, 0x00, 0x09, 0x00}, /*"#", 3*/ + {0x18, 0xC0, 0x24, 0x40, 0x7F, 0xE0, 0x22, 0x40, 0x31, 0x80, 0x00, 0x00}, /*"$", 4*/ + {0x18, 0x00, 0x24, 0xC0, 0x1B, 0x00, 0x0D, 0x80, 0x32, 0x40, 0x01, 0x80}, /*"%", 5*/ + {0x03, 0x80, 0x1C, 0x40, 0x27, 0x40, 0x1C, 0x80, 0x07, 0x40, 0x00, 0x40}, /*"&", 6*/ + {0x10, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"'", 7*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x80, 0x20, 0x40, 0x40, 0x20}, /*"(", 8*/ + {0x00, 0x00, 0x40, 0x20, 0x20, 0x40, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00}, /*")", 9*/ + {0x09, 0x00, 0x06, 0x00, 0x1F, 0x80, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00}, /*"*", 10*/ + {0x04, 0x00, 0x04, 0x00, 0x3F, 0x80, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00}, /*"+", 11*/ + {0x00, 0x10, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*", ", 12*/ + {0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00}, /*"-", 13*/ + {0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*".", 14*/ + {0x00, 0x20, 0x01, 0xC0, 0x06, 0x00, 0x38, 0x00, 0x40, 0x00, 0x00, 0x00}, /*"/", 15*/ + {0x1F, 0x80, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40, 0x1F, 0x80, 0x00, 0x00}, /*"0", 16*/ + {0x00, 0x00, 0x10, 0x40, 0x3F, 0xC0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00}, /*"1", 17*/ + {0x18, 0xC0, 0x21, 0x40, 0x22, 0x40, 0x24, 0x40, 0x18, 0x40, 0x00, 0x00}, /*"2", 18*/ + {0x10, 0x80, 0x20, 0x40, 0x24, 0x40, 0x24, 0x40, 0x1B, 0x80, 0x00, 0x00}, /*"3", 19*/ + {0x02, 0x00, 0x0D, 0x00, 0x11, 0x00, 0x3F, 0xC0, 0x01, 0x40, 0x00, 0x00}, /*"4", 20*/ + {0x3C, 0x80, 0x24, 0x40, 0x24, 0x40, 0x24, 0x40, 0x23, 0x80, 0x00, 0x00}, /*"5", 21*/ + {0x1F, 0x80, 0x24, 0x40, 0x24, 0x40, 0x34, 0x40, 0x03, 0x80, 0x00, 0x00}, /*"6", 22*/ + {0x30, 0x00, 0x20, 0x00, 0x27, 0xC0, 0x38, 0x00, 0x20, 0x00, 0x00, 0x00}, /*"7", 23*/ + {0x1B, 0x80, 0x24, 0x40, 0x24, 0x40, 0x24, 0x40, 0x1B, 0x80, 0x00, 0x00}, /*"8", 24*/ + {0x1C, 0x00, 0x22, 0xC0, 0x22, 0x40, 0x22, 0x40, 0x1F, 0x80, 0x00, 0x00}, /*"9", 25*/ + {0x00, 0x00, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*":", 26*/ + {0x00, 0x00, 0x00, 0x00, 0x04, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*";", 27*/ + {0x00, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x11, 0x00, 0x20, 0x80, 0x40, 0x40}, /*"<", 28*/ + {0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x00, 0x00}, /*"=", 29*/ + {0x00, 0x00, 0x40, 0x40, 0x20, 0x80, 0x11, 0x00, 0x0A, 0x00, 0x04, 0x00}, /*">", 30*/ + {0x18, 0x00, 0x20, 0x00, 0x23, 0x40, 0x24, 0x00, 0x18, 0x00, 0x00, 0x00}, /*"?", 31*/ + {0x1F, 0x80, 0x20, 0x40, 0x27, 0x40, 0x29, 0x40, 0x1F, 0x40, 0x00, 0x00}, /*"@", 32*/ + {0x00, 0x40, 0x07, 0xC0, 0x39, 0x00, 0x0F, 0x00, 0x01, 0xC0, 0x00, 0x40}, /*"A", 33*/ + {0x20, 0x40, 0x3F, 0xC0, 0x24, 0x40, 0x24, 0x40, 0x1B, 0x80, 0x00, 0x00}, /*"B", 34*/ + {0x1F, 0x80, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40, 0x30, 0x80, 0x00, 0x00}, /*"C", 35*/ + {0x20, 0x40, 0x3F, 0xC0, 0x20, 0x40, 0x20, 0x40, 0x1F, 0x80, 0x00, 0x00}, /*"D", 36*/ + {0x20, 0x40, 0x3F, 0xC0, 0x24, 0x40, 0x2E, 0x40, 0x30, 0xC0, 0x00, 0x00}, /*"E", 37*/ + {0x20, 0x40, 0x3F, 0xC0, 0x24, 0x40, 0x2E, 0x00, 0x30, 0x00, 0x00, 0x00}, /*"F", 38*/ + {0x0F, 0x00, 0x10, 0x80, 0x20, 0x40, 0x22, 0x40, 0x33, 0x80, 0x02, 0x00}, /*"G", 39*/ + {0x20, 0x40, 0x3F, 0xC0, 0x04, 0x00, 0x04, 0x00, 0x3F, 0xC0, 0x20, 0x40}, /*"H", 40*/ + {0x20, 0x40, 0x20, 0x40, 0x3F, 0xC0, 0x20, 0x40, 0x20, 0x40, 0x00, 0x00}, /*"I", 41*/ + {0x00, 0x60, 0x20, 0x20, 0x20, 0x20, 0x3F, 0xC0, 0x20, 0x00, 0x20, 0x00}, /*"J", 42*/ + {0x20, 0x40, 0x3F, 0xC0, 0x24, 0x40, 0x0B, 0x00, 0x30, 0xC0, 0x20, 0x40}, /*"K", 43*/ + {0x20, 0x40, 0x3F, 0xC0, 0x20, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xC0}, /*"L", 44*/ + {0x3F, 0xC0, 0x3C, 0x00, 0x03, 0xC0, 0x3C, 0x00, 0x3F, 0xC0, 0x00, 0x00}, /*"M", 45*/ + {0x20, 0x40, 0x3F, 0xC0, 0x0C, 0x40, 0x23, 0x00, 0x3F, 0xC0, 0x20, 0x00}, /*"N", 46*/ + {0x1F, 0x80, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40, 0x1F, 0x80, 0x00, 0x00}, /*"O", 47*/ + {0x20, 0x40, 0x3F, 0xC0, 0x24, 0x40, 0x24, 0x00, 0x18, 0x00, 0x00, 0x00}, /*"P", 48*/ + {0x1F, 0x80, 0x21, 0x40, 0x21, 0x40, 0x20, 0xE0, 0x1F, 0xA0, 0x00, 0x00}, /*"Q", 49*/ + {0x20, 0x40, 0x3F, 0xC0, 0x24, 0x40, 0x26, 0x00, 0x19, 0xC0, 0x00, 0x40}, /*"R", 50*/ + {0x18, 0xC0, 0x24, 0x40, 0x24, 0x40, 0x22, 0x40, 0x31, 0x80, 0x00, 0x00}, /*"S", 51*/ + {0x30, 0x00, 0x20, 0x40, 0x3F, 0xC0, 0x20, 0x40, 0x30, 0x00, 0x00, 0x00}, /*"T", 52*/ + {0x20, 0x00, 0x3F, 0x80, 0x00, 0x40, 0x00, 0x40, 0x3F, 0x80, 0x20, 0x00}, /*"U", 53*/ + {0x20, 0x00, 0x3E, 0x00, 0x01, 0xC0, 0x07, 0x00, 0x38, 0x00, 0x20, 0x00}, /*"V", 54*/ + {0x38, 0x00, 0x07, 0xC0, 0x3C, 0x00, 0x07, 0xC0, 0x38, 0x00, 0x00, 0x00}, /*"W", 55*/ + {0x20, 0x40, 0x39, 0xC0, 0x06, 0x00, 0x39, 0xC0, 0x20, 0x40, 0x00, 0x00}, /*"X", 56*/ + {0x20, 0x00, 0x38, 0x40, 0x07, 0xC0, 0x38, 0x40, 0x20, 0x00, 0x00, 0x00}, /*"Y", 57*/ + {0x30, 0x40, 0x21, 0xC0, 0x26, 0x40, 0x38, 0x40, 0x20, 0xC0, 0x00, 0x00}, /*"Z", 58*/ + {0x00, 0x00, 0x00, 0x00, 0x7F, 0xE0, 0x40, 0x20, 0x40, 0x20, 0x00, 0x00}, /*"[", 59*/ + {0x00, 0x00, 0x70, 0x00, 0x0C, 0x00, 0x03, 0x80, 0x00, 0x40, 0x00, 0x00}, /*"\", 60*/ + {0x00, 0x00, 0x40, 0x20, 0x40, 0x20, 0x7F, 0xE0, 0x00, 0x00, 0x00, 0x00}, /*"]", 61*/ + {0x00, 0x00, 0x20, 0x00, 0x40, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"^", 62*/ + {0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10}, /*"_", 63*/ + {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"`", 64*/ + {0x00, 0x00, 0x02, 0x80, 0x05, 0x40, 0x05, 0x40, 0x03, 0xC0, 0x00, 0x40}, /*"a", 65*/ + {0x20, 0x00, 0x3F, 0xC0, 0x04, 0x40, 0x04, 0x40, 0x03, 0x80, 0x00, 0x00}, /*"b", 66*/ + {0x00, 0x00, 0x03, 0x80, 0x04, 0x40, 0x04, 0x40, 0x06, 0x40, 0x00, 0x00}, /*"c", 67*/ + {0x00, 0x00, 0x03, 0x80, 0x04, 0x40, 0x24, 0x40, 0x3F, 0xC0, 0x00, 0x40}, /*"d", 68*/ + {0x00, 0x00, 0x03, 0x80, 0x05, 0x40, 0x05, 0x40, 0x03, 0x40, 0x00, 0x00}, /*"e", 69*/ + {0x00, 0x00, 0x04, 0x40, 0x1F, 0xC0, 0x24, 0x40, 0x24, 0x40, 0x20, 0x00}, /*"f", 70*/ + {0x00, 0x00, 0x02, 0xE0, 0x05, 0x50, 0x05, 0x50, 0x06, 0x50, 0x04, 0x20}, /*"g", 71*/ + {0x20, 0x40, 0x3F, 0xC0, 0x04, 0x40, 0x04, 0x00, 0x03, 0xC0, 0x00, 0x40}, /*"h", 72*/ + {0x00, 0x00, 0x04, 0x40, 0x27, 0xC0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00}, /*"i", 73*/ + {0x00, 0x10, 0x00, 0x10, 0x04, 0x10, 0x27, 0xE0, 0x00, 0x00, 0x00, 0x00}, /*"j", 74*/ + {0x20, 0x40, 0x3F, 0xC0, 0x01, 0x40, 0x07, 0x00, 0x04, 0xC0, 0x04, 0x40}, /*"k", 75*/ + {0x20, 0x40, 0x20, 0x40, 0x3F, 0xC0, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00}, /*"l", 76*/ + {0x07, 0xC0, 0x04, 0x00, 0x07, 0xC0, 0x04, 0x00, 0x03, 0xC0, 0x00, 0x00}, /*"m", 77*/ + {0x04, 0x40, 0x07, 0xC0, 0x04, 0x40, 0x04, 0x00, 0x03, 0xC0, 0x00, 0x40}, /*"n", 78*/ + {0x00, 0x00, 0x03, 0x80, 0x04, 0x40, 0x04, 0x40, 0x03, 0x80, 0x00, 0x00}, /*"o", 79*/ + {0x04, 0x10, 0x07, 0xF0, 0x04, 0x50, 0x04, 0x40, 0x03, 0x80, 0x00, 0x00}, /*"p", 80*/ + {0x00, 0x00, 0x03, 0x80, 0x04, 0x40, 0x04, 0x50, 0x07, 0xF0, 0x00, 0x10}, /*"q", 81*/ + {0x04, 0x40, 0x07, 0xC0, 0x02, 0x40, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00}, /*"r", 82*/ + {0x00, 0x00, 0x06, 0x40, 0x05, 0x40, 0x05, 0x40, 0x04, 0xC0, 0x00, 0x00}, /*"s", 83*/ + {0x00, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x04, 0x40, 0x00, 0x40, 0x00, 0x00}, /*"t", 84*/ + {0x04, 0x00, 0x07, 0x80, 0x00, 0x40, 0x04, 0x40, 0x07, 0xC0, 0x00, 0x40}, /*"u", 85*/ + {0x04, 0x00, 0x07, 0x00, 0x04, 0xC0, 0x01, 0x80, 0x06, 0x00, 0x04, 0x00}, /*"v", 86*/ + {0x06, 0x00, 0x01, 0xC0, 0x07, 0x00, 0x01, 0xC0, 0x06, 0x00, 0x00, 0x00}, /*"w", 87*/ + {0x04, 0x40, 0x06, 0xC0, 0x01, 0x00, 0x06, 0xC0, 0x04, 0x40, 0x00, 0x00}, /*"x", 88*/ + {0x04, 0x10, 0x07, 0x10, 0x04, 0xE0, 0x01, 0x80, 0x06, 0x00, 0x04, 0x00}, /*"y", 89*/ + {0x00, 0x00, 0x04, 0x40, 0x05, 0xC0, 0x06, 0x40, 0x04, 0x40, 0x00, 0x00}, /*"z", 90*/ + {0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x7B, 0xE0, 0x40, 0x20, 0x00, 0x00}, /*"{", 91*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00}, /*"|", 92*/ + {0x00, 0x00, 0x40, 0x20, 0x7B, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"}", 93*/ + {0x40, 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x20, 0x00, 0x40, 0x00}, /*"~", 94*/ +}; + +static const uint8_t gsc_ssd1306_ascii_1608[95][16] = +{ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*" ", 0*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xCC, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"!", 1*/ + {0x00, 0x00, 0x08, 0x00, 0x30, 0x00, 0x60, 0x00, 0x08, 0x00, 0x30, 0x00, 0x60, 0x00, 0x00, 0x00}, /*""", 2*/ + {0x02, 0x20, 0x03, 0xFC, 0x1E, 0x20, 0x02, 0x20, 0x03, 0xFC, 0x1E, 0x20, 0x02, 0x20, 0x00, 0x00}, /*"#", 3*/ + {0x00, 0x00, 0x0E, 0x18, 0x11, 0x04, 0x3F, 0xFF, 0x10, 0x84, 0x0C, 0x78, 0x00, 0x00, 0x00, 0x00}, /*"$", 4*/ + {0x0F, 0x00, 0x10, 0x84, 0x0F, 0x38, 0x00, 0xC0, 0x07, 0x78, 0x18, 0x84, 0x00, 0x78, 0x00, 0x00}, /*"%", 5*/ + {0x00, 0x78, 0x0F, 0x84, 0x10, 0xC4, 0x11, 0x24, 0x0E, 0x98, 0x00, 0xE4, 0x00, 0x84, 0x00, 0x08}, /*"&", 6*/ + {0x08, 0x00, 0x68, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"'", 7*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xE0, 0x18, 0x18, 0x20, 0x04, 0x40, 0x02, 0x00, 0x00}, /*"(", 8*/ + {0x00, 0x00, 0x40, 0x02, 0x20, 0x04, 0x18, 0x18, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*")", 9*/ + {0x02, 0x40, 0x02, 0x40, 0x01, 0x80, 0x0F, 0xF0, 0x01, 0x80, 0x02, 0x40, 0x02, 0x40, 0x00, 0x00}, /*"*", 10*/ + {0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x0F, 0xF8, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00}, /*"+", 11*/ + {0x00, 0x01, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*", ", 12*/ + {0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80}, /*"-", 13*/ + {0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*".", 14*/ + {0x00, 0x00, 0x00, 0x06, 0x00, 0x18, 0x00, 0x60, 0x01, 0x80, 0x06, 0x00, 0x18, 0x00, 0x20, 0x00}, /*"/", 15*/ + {0x00, 0x00, 0x07, 0xF0, 0x08, 0x08, 0x10, 0x04, 0x10, 0x04, 0x08, 0x08, 0x07, 0xF0, 0x00, 0x00}, /*"0", 16*/ + {0x00, 0x00, 0x08, 0x04, 0x08, 0x04, 0x1F, 0xFC, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, /*"1", 17*/ + {0x00, 0x00, 0x0E, 0x0C, 0x10, 0x14, 0x10, 0x24, 0x10, 0x44, 0x11, 0x84, 0x0E, 0x0C, 0x00, 0x00}, /*"2", 18*/ + {0x00, 0x00, 0x0C, 0x18, 0x10, 0x04, 0x11, 0x04, 0x11, 0x04, 0x12, 0x88, 0x0C, 0x70, 0x00, 0x00}, /*"3", 19*/ + {0x00, 0x00, 0x00, 0xE0, 0x03, 0x20, 0x04, 0x24, 0x08, 0x24, 0x1F, 0xFC, 0x00, 0x24, 0x00, 0x00}, /*"4", 20*/ + {0x00, 0x00, 0x1F, 0x98, 0x10, 0x84, 0x11, 0x04, 0x11, 0x04, 0x10, 0x88, 0x10, 0x70, 0x00, 0x00}, /*"5", 21*/ + {0x00, 0x00, 0x07, 0xF0, 0x08, 0x88, 0x11, 0x04, 0x11, 0x04, 0x18, 0x88, 0x00, 0x70, 0x00, 0x00}, /*"6", 22*/ + {0x00, 0x00, 0x1C, 0x00, 0x10, 0x00, 0x10, 0xFC, 0x13, 0x00, 0x1C, 0x00, 0x10, 0x00, 0x00, 0x00}, /*"7", 23*/ + {0x00, 0x00, 0x0E, 0x38, 0x11, 0x44, 0x10, 0x84, 0x10, 0x84, 0x11, 0x44, 0x0E, 0x38, 0x00, 0x00}, /*"8", 24*/ + {0x00, 0x00, 0x07, 0x00, 0x08, 0x8C, 0x10, 0x44, 0x10, 0x44, 0x08, 0x88, 0x07, 0xF0, 0x00, 0x00}, /*"9", 25*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0C, 0x03, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*":", 26*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*";", 27*/ + {0x00, 0x00, 0x00, 0x80, 0x01, 0x40, 0x02, 0x20, 0x04, 0x10, 0x08, 0x08, 0x10, 0x04, 0x00, 0x00}, /*"<", 28*/ + {0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x00, 0x00}, /*"=", 29*/ + {0x00, 0x00, 0x10, 0x04, 0x08, 0x08, 0x04, 0x10, 0x02, 0x20, 0x01, 0x40, 0x00, 0x80, 0x00, 0x00}, /*">", 30*/ + {0x00, 0x00, 0x0E, 0x00, 0x12, 0x00, 0x10, 0x0C, 0x10, 0x6C, 0x10, 0x80, 0x0F, 0x00, 0x00, 0x00}, /*"?", 31*/ + {0x03, 0xE0, 0x0C, 0x18, 0x13, 0xE4, 0x14, 0x24, 0x17, 0xC4, 0x08, 0x28, 0x07, 0xD0, 0x00, 0x00}, /*"@", 32*/ + {0x00, 0x04, 0x00, 0x3C, 0x03, 0xC4, 0x1C, 0x40, 0x07, 0x40, 0x00, 0xE4, 0x00, 0x1C, 0x00, 0x04}, /*"A", 33*/ + {0x10, 0x04, 0x1F, 0xFC, 0x11, 0x04, 0x11, 0x04, 0x11, 0x04, 0x0E, 0x88, 0x00, 0x70, 0x00, 0x00}, /*"B", 34*/ + {0x03, 0xE0, 0x0C, 0x18, 0x10, 0x04, 0x10, 0x04, 0x10, 0x04, 0x10, 0x08, 0x1C, 0x10, 0x00, 0x00}, /*"C", 35*/ + {0x10, 0x04, 0x1F, 0xFC, 0x10, 0x04, 0x10, 0x04, 0x10, 0x04, 0x08, 0x08, 0x07, 0xF0, 0x00, 0x00}, /*"D", 36*/ + {0x10, 0x04, 0x1F, 0xFC, 0x11, 0x04, 0x11, 0x04, 0x17, 0xC4, 0x10, 0x04, 0x08, 0x18, 0x00, 0x00}, /*"E", 37*/ + {0x10, 0x04, 0x1F, 0xFC, 0x11, 0x04, 0x11, 0x00, 0x17, 0xC0, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00}, /*"F", 38*/ + {0x03, 0xE0, 0x0C, 0x18, 0x10, 0x04, 0x10, 0x04, 0x10, 0x44, 0x1C, 0x78, 0x00, 0x40, 0x00, 0x00}, /*"G", 39*/ + {0x10, 0x04, 0x1F, 0xFC, 0x10, 0x84, 0x00, 0x80, 0x00, 0x80, 0x10, 0x84, 0x1F, 0xFC, 0x10, 0x04}, /*"H", 40*/ + {0x00, 0x00, 0x10, 0x04, 0x10, 0x04, 0x1F, 0xFC, 0x10, 0x04, 0x10, 0x04, 0x00, 0x00, 0x00, 0x00}, /*"I", 41*/ + {0x00, 0x03, 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x1F, 0xFE, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00}, /*"J", 42*/ + {0x10, 0x04, 0x1F, 0xFC, 0x11, 0x04, 0x03, 0x80, 0x14, 0x64, 0x18, 0x1C, 0x10, 0x04, 0x00, 0x00}, /*"K", 43*/ + {0x10, 0x04, 0x1F, 0xFC, 0x10, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00}, /*"L", 44*/ + {0x10, 0x04, 0x1F, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x1F, 0xFC, 0x10, 0x04, 0x00, 0x00}, /*"M", 45*/ + {0x10, 0x04, 0x1F, 0xFC, 0x0C, 0x04, 0x03, 0x00, 0x00, 0xE0, 0x10, 0x18, 0x1F, 0xFC, 0x10, 0x00}, /*"N", 46*/ + {0x07, 0xF0, 0x08, 0x08, 0x10, 0x04, 0x10, 0x04, 0x10, 0x04, 0x08, 0x08, 0x07, 0xF0, 0x00, 0x00}, /*"O", 47*/ + {0x10, 0x04, 0x1F, 0xFC, 0x10, 0x84, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x0F, 0x00, 0x00, 0x00}, /*"P", 48*/ + {0x07, 0xF0, 0x08, 0x18, 0x10, 0x24, 0x10, 0x24, 0x10, 0x1C, 0x08, 0x0A, 0x07, 0xF2, 0x00, 0x00}, /*"Q", 49*/ + {0x10, 0x04, 0x1F, 0xFC, 0x11, 0x04, 0x11, 0x00, 0x11, 0xC0, 0x11, 0x30, 0x0E, 0x0C, 0x00, 0x04}, /*"R", 50*/ + {0x00, 0x00, 0x0E, 0x1C, 0x11, 0x04, 0x10, 0x84, 0x10, 0x84, 0x10, 0x44, 0x1C, 0x38, 0x00, 0x00}, /*"S", 51*/ + {0x18, 0x00, 0x10, 0x00, 0x10, 0x04, 0x1F, 0xFC, 0x10, 0x04, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00}, /*"T", 52*/ + {0x10, 0x00, 0x1F, 0xF8, 0x10, 0x04, 0x00, 0x04, 0x00, 0x04, 0x10, 0x04, 0x1F, 0xF8, 0x10, 0x00}, /*"U", 53*/ + {0x10, 0x00, 0x1E, 0x00, 0x11, 0xE0, 0x00, 0x1C, 0x00, 0x70, 0x13, 0x80, 0x1C, 0x00, 0x10, 0x00}, /*"V", 54*/ + {0x1F, 0xC0, 0x10, 0x3C, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0xE0, 0x10, 0x3C, 0x1F, 0xC0, 0x00, 0x00}, /*"W", 55*/ + {0x10, 0x04, 0x18, 0x0C, 0x16, 0x34, 0x01, 0xC0, 0x01, 0xC0, 0x16, 0x34, 0x18, 0x0C, 0x10, 0x04}, /*"X", 56*/ + {0x10, 0x00, 0x1C, 0x00, 0x13, 0x04, 0x00, 0xFC, 0x13, 0x04, 0x1C, 0x00, 0x10, 0x00, 0x00, 0x00}, /*"Y", 57*/ + {0x08, 0x04, 0x10, 0x1C, 0x10, 0x64, 0x10, 0x84, 0x13, 0x04, 0x1C, 0x04, 0x10, 0x18, 0x00, 0x00}, /*"Z", 58*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x00, 0x00}, /*"[", 59*/ + {0x00, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x03, 0x80, 0x00, 0x60, 0x00, 0x1C, 0x00, 0x03, 0x00, 0x00}, /*"\", 60*/ + {0x00, 0x00, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x7F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"]", 61*/ + {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x20, 0x00, 0x00, 0x00}, /*"^", 62*/ + {0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01}, /*"_", 63*/ + {0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"`", 64*/ + {0x00, 0x00, 0x00, 0x98, 0x01, 0x24, 0x01, 0x44, 0x01, 0x44, 0x01, 0x44, 0x00, 0xFC, 0x00, 0x04}, /*"a", 65*/ + {0x10, 0x00, 0x1F, 0xFC, 0x00, 0x88, 0x01, 0x04, 0x01, 0x04, 0x00, 0x88, 0x00, 0x70, 0x00, 0x00}, /*"b", 66*/ + {0x00, 0x00, 0x00, 0x70, 0x00, 0x88, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x00, 0x88, 0x00, 0x00}, /*"c", 67*/ + {0x00, 0x00, 0x00, 0x70, 0x00, 0x88, 0x01, 0x04, 0x01, 0x04, 0x11, 0x08, 0x1F, 0xFC, 0x00, 0x04}, /*"d", 68*/ + {0x00, 0x00, 0x00, 0xF8, 0x01, 0x44, 0x01, 0x44, 0x01, 0x44, 0x01, 0x44, 0x00, 0xC8, 0x00, 0x00}, /*"e", 69*/ + {0x00, 0x00, 0x01, 0x04, 0x01, 0x04, 0x0F, 0xFC, 0x11, 0x04, 0x11, 0x04, 0x11, 0x00, 0x18, 0x00}, /*"f", 70*/ + {0x00, 0x00, 0x00, 0xD6, 0x01, 0x29, 0x01, 0x29, 0x01, 0x29, 0x01, 0xC9, 0x01, 0x06, 0x00, 0x00}, /*"g", 71*/ + {0x10, 0x04, 0x1F, 0xFC, 0x00, 0x84, 0x01, 0x00, 0x01, 0x00, 0x01, 0x04, 0x00, 0xFC, 0x00, 0x04}, /*"h", 72*/ + {0x00, 0x00, 0x01, 0x04, 0x19, 0x04, 0x19, 0xFC, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, /*"i", 73*/ + {0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x01, 0x01, 0x19, 0x01, 0x19, 0xFE, 0x00, 0x00, 0x00, 0x00}, /*"j", 74*/ + {0x10, 0x04, 0x1F, 0xFC, 0x00, 0x24, 0x00, 0x40, 0x01, 0xB4, 0x01, 0x0C, 0x01, 0x04, 0x00, 0x00}, /*"k", 75*/ + {0x00, 0x00, 0x10, 0x04, 0x10, 0x04, 0x1F, 0xFC, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, /*"l", 76*/ + {0x01, 0x04, 0x01, 0xFC, 0x01, 0x04, 0x01, 0x00, 0x01, 0xFC, 0x01, 0x04, 0x01, 0x00, 0x00, 0xFC}, /*"m", 77*/ + {0x01, 0x04, 0x01, 0xFC, 0x00, 0x84, 0x01, 0x00, 0x01, 0x00, 0x01, 0x04, 0x00, 0xFC, 0x00, 0x04}, /*"n", 78*/ + {0x00, 0x00, 0x00, 0xF8, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x00, 0xF8, 0x00, 0x00}, /*"o", 79*/ + {0x01, 0x01, 0x01, 0xFF, 0x00, 0x85, 0x01, 0x04, 0x01, 0x04, 0x00, 0x88, 0x00, 0x70, 0x00, 0x00}, /*"p", 80*/ + {0x00, 0x00, 0x00, 0x70, 0x00, 0x88, 0x01, 0x04, 0x01, 0x04, 0x01, 0x05, 0x01, 0xFF, 0x00, 0x01}, /*"q", 81*/ + {0x01, 0x04, 0x01, 0x04, 0x01, 0xFC, 0x00, 0x84, 0x01, 0x04, 0x01, 0x00, 0x01, 0x80, 0x00, 0x00}, /*"r", 82*/ + {0x00, 0x00, 0x00, 0xCC, 0x01, 0x24, 0x01, 0x24, 0x01, 0x24, 0x01, 0x24, 0x01, 0x98, 0x00, 0x00}, /*"s", 83*/ + {0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x07, 0xF8, 0x01, 0x04, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00}, /*"t", 84*/ + {0x01, 0x00, 0x01, 0xF8, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x01, 0x08, 0x01, 0xFC, 0x00, 0x04}, /*"u", 85*/ + {0x01, 0x00, 0x01, 0x80, 0x01, 0x70, 0x00, 0x0C, 0x00, 0x10, 0x01, 0x60, 0x01, 0x80, 0x01, 0x00}, /*"v", 86*/ + {0x01, 0xF0, 0x01, 0x0C, 0x00, 0x30, 0x01, 0xC0, 0x00, 0x30, 0x01, 0x0C, 0x01, 0xF0, 0x01, 0x00}, /*"w", 87*/ + {0x00, 0x00, 0x01, 0x04, 0x01, 0x8C, 0x00, 0x74, 0x01, 0x70, 0x01, 0x8C, 0x01, 0x04, 0x00, 0x00}, /*"x", 88*/ + {0x01, 0x01, 0x01, 0x81, 0x01, 0x71, 0x00, 0x0E, 0x00, 0x18, 0x01, 0x60, 0x01, 0x80, 0x01, 0x00}, /*"y", 89*/ + {0x00, 0x00, 0x01, 0x84, 0x01, 0x0C, 0x01, 0x34, 0x01, 0x44, 0x01, 0x84, 0x01, 0x0C, 0x00, 0x00}, /*"z", 90*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3E, 0xFC, 0x40, 0x02, 0x40, 0x02}, /*"{", 91*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"|", 92*/ + {0x00, 0x00, 0x40, 0x02, 0x40, 0x02, 0x3E, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"}", 93*/ + {0x00, 0x00, 0x60, 0x00, 0x80, 0x00, 0x80, 0x00, 0x40, 0x00, 0x40, 0x00, 0x20, 0x00, 0x20, 0x00}, /*"~", 94*/ +}; + +static const uint8_t gsc_ssd1306_ascii_2412[95][36] = +{ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*" ", 0*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x80, 0x38, 0x0F, 0xFE, 0x38, 0x0F, 0x80, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"!", 1*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x38, 0x00, 0x00, 0x31, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x38, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00}, /*""", 2*/ + {0x00, 0x00, 0x00, 0x00, 0x61, 0x80, 0x00, 0x67, 0xF8, 0x07, 0xF9, 0x80, 0x00, 0x61, 0x80, 0x00, 0x61, 0x80, 0x00, 0x61, 0x80, 0x00, 0x61, 0x80, 0x00, 0x67, 0xF8, 0x07, 0xF9, 0x80, 0x00, 0x61, 0x80, 0x00, 0x00, 0x00}, /*"#", 3*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xC0, 0xE0, 0x03, 0xE0, 0xF0, 0x06, 0x30, 0x08, 0x04, 0x18, 0x08, 0x1F, 0xFF, 0xFE, 0x04, 0x0E, 0x08, 0x07, 0x87, 0xF0, 0x03, 0x81, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"$", 4*/ + {0x01, 0xF0, 0x00, 0x06, 0x0C, 0x00, 0x04, 0x04, 0x08, 0x06, 0x0C, 0x70, 0x01, 0xF9, 0xC0, 0x00, 0x0E, 0x00, 0x00, 0x3B, 0xE0, 0x00, 0xEC, 0x18, 0x07, 0x08, 0x08, 0x04, 0x0C, 0x18, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x00}, /*"%", 5*/ + {0x00, 0x01, 0xE0, 0x00, 0x07, 0xF0, 0x03, 0xF8, 0x18, 0x04, 0x1C, 0x08, 0x04, 0x17, 0x08, 0x07, 0xE1, 0xD0, 0x03, 0xC0, 0xE0, 0x00, 0x23, 0xB0, 0x00, 0x3C, 0x08, 0x00, 0x20, 0x08, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, /*"&", 6*/ + {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x31, 0x00, 0x00, 0x32, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"'", 7*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x01, 0xFF, 0xC0, 0x07, 0x80, 0xF0, 0x0C, 0x00, 0x18, 0x10, 0x00, 0x04, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00}, /*"(", 8*/ + {0x00, 0x00, 0x00, 0x20, 0x00, 0x02, 0x10, 0x00, 0x04, 0x0C, 0x00, 0x18, 0x07, 0x80, 0xF0, 0x01, 0xFF, 0xC0, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*")", 9*/ + {0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x66, 0x00, 0x00, 0x66, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x18, 0x00, 0x03, 0xFF, 0xC0, 0x00, 0x18, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x66, 0x00, 0x00, 0x66, 0x00, 0x00, 0x42, 0x00}, /*"*", 10*/ + {0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00}, /*"+", 11*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x31, 0x00, 0x00, 0x32, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*", ", 12*/ + {0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00}, /*"-", 13*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x38, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*".", 14*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x70, 0x00, 0x01, 0x80, 0x00, 0x0E, 0x00, 0x00, 0x38, 0x00, 0x00, 0xC0, 0x00, 0x07, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"/", 15*/ + {0x00, 0x00, 0x00, 0x00, 0x7F, 0x80, 0x01, 0xFF, 0xE0, 0x03, 0x80, 0x70, 0x06, 0x00, 0x18, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x06, 0x00, 0x18, 0x03, 0x80, 0x70, 0x01, 0xFF, 0xE0, 0x00, 0x7F, 0x80, 0x00, 0x00, 0x00}, /*"0", 16*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x01, 0x00, 0x08, 0x01, 0x00, 0x08, 0x03, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"1", 17*/ + {0x00, 0x00, 0x00, 0x01, 0xC0, 0x38, 0x02, 0xC0, 0x58, 0x04, 0x00, 0x98, 0x04, 0x01, 0x18, 0x04, 0x02, 0x18, 0x04, 0x04, 0x18, 0x06, 0x1C, 0x18, 0x03, 0xF8, 0x18, 0x01, 0xE0, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"2", 18*/ + {0x00, 0x00, 0x00, 0x01, 0xC0, 0xE0, 0x03, 0xC0, 0xF0, 0x04, 0x00, 0x08, 0x04, 0x08, 0x08, 0x04, 0x08, 0x08, 0x06, 0x18, 0x08, 0x03, 0xF4, 0x18, 0x01, 0xE7, 0xF0, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"3", 19*/ + {0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x11, 0x00, 0x00, 0x61, 0x00, 0x00, 0x81, 0x08, 0x03, 0x01, 0x08, 0x07, 0xFF, 0xF8, 0x0F, 0xFF, 0xF8, 0x00, 0x01, 0x08, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00}, /*"4", 20*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x07, 0xFC, 0xD0, 0x06, 0x08, 0x08, 0x06, 0x10, 0x08, 0x06, 0x10, 0x08, 0x06, 0x10, 0x08, 0x06, 0x18, 0x38, 0x06, 0x0F, 0xF0, 0x06, 0x07, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"5", 21*/ + {0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x01, 0xFF, 0xE0, 0x03, 0x84, 0x30, 0x02, 0x08, 0x18, 0x04, 0x10, 0x08, 0x04, 0x10, 0x08, 0x04, 0x10, 0x08, 0x07, 0x18, 0x10, 0x03, 0x0F, 0xF0, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x00}, /*"6", 22*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x07, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0xF8, 0x06, 0x07, 0xF8, 0x06, 0x18, 0x00, 0x06, 0xE0, 0x00, 0x07, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"7", 23*/ + {0x00, 0x00, 0x00, 0x01, 0xE1, 0xE0, 0x03, 0xF7, 0xF0, 0x06, 0x34, 0x10, 0x04, 0x18, 0x08, 0x04, 0x18, 0x08, 0x04, 0x0C, 0x08, 0x04, 0x0C, 0x08, 0x06, 0x16, 0x18, 0x03, 0xF3, 0xF0, 0x01, 0xC1, 0xE0, 0x00, 0x00, 0x00}, /*"8", 24*/ + {0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x03, 0xFC, 0x30, 0x03, 0x06, 0x38, 0x04, 0x02, 0x08, 0x04, 0x02, 0x08, 0x04, 0x02, 0x08, 0x04, 0x04, 0x10, 0x03, 0x08, 0xF0, 0x01, 0xFF, 0xC0, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00}, /*"9", 25*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x38, 0x00, 0x70, 0x38, 0x00, 0x70, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*":", 26*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x1A, 0x00, 0x30, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*";", 27*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x14, 0x00, 0x00, 0x22, 0x00, 0x00, 0x41, 0x00, 0x00, 0x80, 0x80, 0x01, 0x00, 0x40, 0x02, 0x00, 0x20, 0x04, 0x00, 0x10, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00}, /*"<", 28*/ + {0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x21, 0x00, 0x00, 0x21, 0x00, 0x00, 0x21, 0x00, 0x00, 0x21, 0x00, 0x00, 0x21, 0x00, 0x00, 0x21, 0x00, 0x00, 0x21, 0x00, 0x00, 0x21, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00}, /*"=", 29*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x04, 0x00, 0x10, 0x02, 0x00, 0x20, 0x01, 0x00, 0x40, 0x00, 0x80, 0x80, 0x00, 0x41, 0x00, 0x00, 0x22, 0x00, 0x00, 0x14, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00}, /*">", 30*/ + {0x00, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x04, 0xC0, 0x00, 0x04, 0x00, 0x00, 0x08, 0x00, 0x38, 0x08, 0x0F, 0x38, 0x08, 0x08, 0x38, 0x08, 0x10, 0x00, 0x0C, 0x30, 0x00, 0x07, 0xE0, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x00}, /*"?", 31*/ + {0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0xFF, 0xE0, 0x03, 0x80, 0x70, 0x02, 0x0F, 0x10, 0x06, 0x70, 0x88, 0x04, 0xC0, 0x88, 0x04, 0x83, 0x08, 0x04, 0x7F, 0x88, 0x02, 0xC0, 0x90, 0x03, 0x01, 0x20, 0x00, 0xFE, 0x40}, /*"@", 32*/ + {0x00, 0x00, 0x08, 0x00, 0x00, 0x18, 0x00, 0x01, 0xF8, 0x00, 0x3E, 0x08, 0x01, 0xC2, 0x00, 0x07, 0x02, 0x00, 0x07, 0xE2, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x1F, 0xC8, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x38, 0x00, 0x00, 0x08}, /*"A", 33*/ + {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x08, 0x08, 0x04, 0x08, 0x08, 0x04, 0x08, 0x08, 0x04, 0x08, 0x08, 0x06, 0x18, 0x08, 0x03, 0xF4, 0x18, 0x01, 0xE7, 0xF0, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x00}, /*"B", 34*/ + {0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x01, 0xFF, 0xE0, 0x03, 0x80, 0x70, 0x02, 0x00, 0x18, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x04, 0x00, 0x10, 0x06, 0x00, 0x20, 0x07, 0x80, 0xC0, 0x00, 0x00, 0x00}, /*"C", 35*/ + {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x04, 0x00, 0x18, 0x02, 0x00, 0x10, 0x03, 0x80, 0x70, 0x01, 0xFF, 0xE0, 0x00, 0x7F, 0x80, 0x00, 0x00, 0x00}, /*"D", 36*/ + {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x08, 0x08, 0x04, 0x08, 0x08, 0x04, 0x08, 0x08, 0x04, 0x08, 0x08, 0x04, 0x3E, 0x08, 0x04, 0x00, 0x08, 0x06, 0x00, 0x18, 0x01, 0x00, 0x60, 0x00, 0x00, 0x00}, /*"E", 37*/ + {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x08, 0x08, 0x04, 0x08, 0x00, 0x04, 0x08, 0x00, 0x04, 0x08, 0x00, 0x04, 0x3E, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00}, /*"F", 38*/ + {0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x01, 0xFF, 0xE0, 0x03, 0x80, 0x70, 0x06, 0x00, 0x18, 0x04, 0x00, 0x08, 0x04, 0x02, 0x08, 0x04, 0x02, 0x08, 0x02, 0x03, 0xF0, 0x07, 0x83, 0xF0, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00}, /*"G", 39*/ + {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x04, 0x08, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x00, 0x08}, /*"H", 40*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"I", 41*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x07, 0x00, 0x00, 0x01, 0x04, 0x00, 0x01, 0x04, 0x00, 0x01, 0x04, 0x00, 0x03, 0x07, 0xFF, 0xFE, 0x07, 0xFF, 0xFC, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00}, /*"J", 42*/ + {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x0C, 0x08, 0x00, 0x18, 0x00, 0x00, 0x3E, 0x00, 0x04, 0xC7, 0x80, 0x05, 0x03, 0xC8, 0x06, 0x00, 0xF8, 0x04, 0x00, 0x38, 0x04, 0x00, 0x18, 0x00, 0x00, 0x08}, /*"K", 43*/ + {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00}, /*"L", 44*/ + {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0x80, 0x08, 0x07, 0xFC, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x03, 0xF8, 0x00, 0x07, 0xC0, 0x00, 0x78, 0x00, 0x07, 0x80, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x00, 0x08}, /*"M", 45*/ + {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0x00, 0x08, 0x03, 0xC0, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x38, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, 0x00, 0x00, 0x01, 0xC0, 0x04, 0x00, 0xF0, 0x07, 0xFF, 0xF8, 0x04, 0x00, 0x00}, /*"N", 46*/ + {0x00, 0x00, 0x00, 0x00, 0x7F, 0x80, 0x01, 0xFF, 0xE0, 0x03, 0x80, 0x70, 0x06, 0x00, 0x18, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x06, 0x00, 0x18, 0x03, 0x00, 0x30, 0x01, 0xFF, 0xE0, 0x00, 0x7F, 0x80, 0x00, 0x00, 0x00}, /*"O", 47*/ + {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x04, 0x08, 0x04, 0x04, 0x00, 0x04, 0x04, 0x00, 0x04, 0x04, 0x00, 0x04, 0x04, 0x00, 0x06, 0x0C, 0x00, 0x03, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x00, 0x00}, /*"P", 48*/ + {0x00, 0x00, 0x00, 0x00, 0x7F, 0x80, 0x01, 0xFF, 0xE0, 0x03, 0x80, 0x70, 0x06, 0x00, 0x88, 0x04, 0x00, 0x88, 0x04, 0x00, 0xC8, 0x06, 0x00, 0x3C, 0x03, 0x00, 0x3E, 0x01, 0xFF, 0xE6, 0x00, 0x7F, 0x84, 0x00, 0x00, 0x00}, /*"Q", 49*/ + {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x08, 0x08, 0x04, 0x08, 0x00, 0x04, 0x0C, 0x00, 0x04, 0x0F, 0x00, 0x04, 0x0B, 0xC0, 0x06, 0x10, 0xF0, 0x03, 0xF0, 0x38, 0x01, 0xE0, 0x08, 0x00, 0x00, 0x08}, /*"R", 50*/ + {0x00, 0x00, 0x00, 0x01, 0xE0, 0xF8, 0x03, 0xF0, 0x30, 0x06, 0x30, 0x10, 0x04, 0x18, 0x08, 0x04, 0x18, 0x08, 0x04, 0x0C, 0x08, 0x04, 0x0C, 0x08, 0x02, 0x06, 0x18, 0x02, 0x07, 0xF0, 0x07, 0x81, 0xE0, 0x00, 0x00, 0x00}, /*"S", 51*/ + {0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x00, 0x08, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00, 0x00, 0x01, 0x80, 0x00}, /*"T", 52*/ + {0x04, 0x00, 0x00, 0x07, 0xFF, 0xE0, 0x07, 0xFF, 0xF0, 0x04, 0x00, 0x18, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x04, 0x00, 0x10, 0x07, 0xFF, 0xE0, 0x04, 0x00, 0x00}, /*"U", 53*/ + {0x04, 0x00, 0x00, 0x06, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x07, 0xFE, 0x00, 0x04, 0x1F, 0xE0, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x38, 0x00, 0x01, 0xE0, 0x04, 0x3E, 0x00, 0x07, 0xC0, 0x00, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00}, /*"V", 54*/ + {0x04, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x07, 0xFF, 0xC0, 0x04, 0x1F, 0xF8, 0x00, 0x07, 0xC0, 0x07, 0xF8, 0x00, 0x07, 0xFF, 0x80, 0x04, 0x3F, 0xF8, 0x00, 0x07, 0xC0, 0x04, 0xF8, 0x00, 0x07, 0x00, 0x00, 0x04, 0x00, 0x00}, /*"W", 55*/ + {0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x06, 0x00, 0x18, 0x07, 0xC0, 0x78, 0x05, 0xF1, 0xC8, 0x00, 0x3E, 0x00, 0x00, 0x1F, 0x80, 0x04, 0x63, 0xE8, 0x07, 0x80, 0xF8, 0x06, 0x00, 0x18, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00}, /*"X", 56*/ + {0x04, 0x00, 0x00, 0x06, 0x00, 0x00, 0x07, 0x80, 0x00, 0x07, 0xE0, 0x08, 0x04, 0x7C, 0x08, 0x00, 0x1F, 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x18, 0x08, 0x04, 0xE0, 0x08, 0x07, 0x00, 0x00, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00}, /*"Y", 57*/ + {0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x06, 0x00, 0x38, 0x04, 0x00, 0xF8, 0x04, 0x03, 0xE8, 0x04, 0x0F, 0x08, 0x04, 0x7C, 0x08, 0x05, 0xF0, 0x08, 0x07, 0xC0, 0x08, 0x07, 0x00, 0x18, 0x04, 0x00, 0x60, 0x00, 0x00, 0x00}, /*"Z", 58*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x20, 0x00, 0x02, 0x20, 0x00, 0x02, 0x20, 0x00, 0x02, 0x20, 0x00, 0x02, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00}, /*"[", 59*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x38, 0x00, 0x00, 0x06, 0x00, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x30, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}, /*"\", 60*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x02, 0x20, 0x00, 0x02, 0x20, 0x00, 0x02, 0x20, 0x00, 0x02, 0x20, 0x00, 0x02, 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"]", 61*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x00, 0x00, 0x30, 0x00, 0x00, 0x20, 0x00, 0x00, 0x30, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"^", 62*/ + {0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01}, /*"_", 63*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"`", 64*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x19, 0xF8, 0x00, 0x1B, 0x18, 0x00, 0x22, 0x08, 0x00, 0x26, 0x08, 0x00, 0x24, 0x08, 0x00, 0x24, 0x10, 0x00, 0x3F, 0xF8, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x08, 0x00, 0x00, 0x18}, /*"a", 65*/ + {0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x07, 0xFF, 0xF8, 0x0F, 0xFF, 0xF0, 0x00, 0x18, 0x18, 0x00, 0x10, 0x08, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x30, 0x18, 0x00, 0x1F, 0xF0, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00}, /*"b", 66*/ + {0x00, 0x00, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x1F, 0xF0, 0x00, 0x18, 0x30, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x3C, 0x08, 0x00, 0x1C, 0x10, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"c", 67*/ + {0x00, 0x00, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x1F, 0xF0, 0x00, 0x38, 0x18, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x04, 0x10, 0x10, 0x07, 0xFF, 0xF8, 0x0F, 0xFF, 0xF0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, /*"d", 68*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x1F, 0xF0, 0x00, 0x12, 0x30, 0x00, 0x22, 0x18, 0x00, 0x22, 0x08, 0x00, 0x22, 0x08, 0x00, 0x32, 0x08, 0x00, 0x1E, 0x10, 0x00, 0x0E, 0x20, 0x00, 0x00, 0x00}, /*"e", 69*/ + {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x01, 0xFF, 0xF8, 0x03, 0xFF, 0xF8, 0x06, 0x20, 0x08, 0x04, 0x20, 0x08, 0x04, 0x20, 0x08, 0x07, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"f", 70*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x0E, 0x6E, 0x00, 0x1F, 0xF3, 0x00, 0x31, 0xB1, 0x00, 0x20, 0xB1, 0x00, 0x20, 0xB1, 0x00, 0x31, 0x91, 0x00, 0x1F, 0x13, 0x00, 0x2E, 0x1E, 0x00, 0x20, 0x0E, 0x00, 0x30, 0x00}, /*"g", 71*/ + {0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x0F, 0xFF, 0xF8, 0x00, 0x10, 0x08, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x08, 0x00, 0x3F, 0xF8, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00}, /*"h", 72*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x06, 0x3F, 0xF8, 0x06, 0x3F, 0xF8, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"i", 73*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x20, 0x01, 0x00, 0x20, 0x01, 0x00, 0x20, 0x03, 0x06, 0x3F, 0xFE, 0x06, 0x3F, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"j", 74*/ + {0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x0F, 0xFF, 0xF8, 0x00, 0x01, 0x88, 0x00, 0x03, 0x00, 0x00, 0x2F, 0xC0, 0x00, 0x38, 0xF8, 0x00, 0x20, 0x38, 0x00, 0x20, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00}, /*"k", 75*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"l", 76*/ + {0x00, 0x20, 0x08, 0x00, 0x3F, 0xF8, 0x00, 0x3F, 0xF8, 0x00, 0x10, 0x08, 0x00, 0x20, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x3F, 0xF8, 0x00, 0x10, 0x08, 0x00, 0x20, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x08}, /*"m", 77*/ + {0x00, 0x00, 0x00, 0x00, 0x20, 0x08, 0x00, 0x3F, 0xF8, 0x00, 0x3F, 0xF8, 0x00, 0x10, 0x08, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x08, 0x00, 0x3F, 0xF8, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00}, /*"n", 78*/ + {0x00, 0x00, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0xF0, 0x00, 0x18, 0x30, 0x00, 0x30, 0x08, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x30, 0x08, 0x00, 0x18, 0x30, 0x00, 0x0F, 0xF0, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x00}, /*"o", 79*/ + {0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x3F, 0xFF, 0x00, 0x3F, 0xFF, 0x00, 0x10, 0x11, 0x00, 0x20, 0x09, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x30, 0x38, 0x00, 0x1F, 0xF0, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00}, /*"p", 80*/ + {0x00, 0x00, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x1F, 0xF0, 0x00, 0x38, 0x18, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x20, 0x09, 0x00, 0x10, 0x11, 0x00, 0x1F, 0xFF, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}, /*"q", 81*/ + {0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x3F, 0xF8, 0x00, 0x3F, 0xF8, 0x00, 0x08, 0x08, 0x00, 0x10, 0x08, 0x00, 0x20, 0x08, 0x00, 0x20, 0x00, 0x00, 0x30, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00}, /*"r", 82*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x78, 0x00, 0x1E, 0x18, 0x00, 0x33, 0x08, 0x00, 0x23, 0x08, 0x00, 0x21, 0x08, 0x00, 0x21, 0x88, 0x00, 0x21, 0x98, 0x00, 0x30, 0xF0, 0x00, 0x38, 0x60, 0x00, 0x00, 0x00}, /*"s", 83*/ + {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0xFF, 0xF0, 0x03, 0xFF, 0xF8, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"t", 84*/ + {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x18, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x20, 0x10, 0x00, 0x3F, 0xF8, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, /*"u", 85*/ + {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x30, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x23, 0xF0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x70, 0x00, 0x23, 0x80, 0x00, 0x3C, 0x00, 0x00, 0x30, 0x00, 0x00, 0x20, 0x00}, /*"v", 86*/ + {0x00, 0x20, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x23, 0xF8, 0x00, 0x00, 0xE0, 0x00, 0x27, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x21, 0xF8, 0x00, 0x01, 0xE0, 0x00, 0x3E, 0x00, 0x00, 0x20, 0x00}, /*"w", 87*/ + {0x00, 0x00, 0x00, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x38, 0x38, 0x00, 0x3E, 0x68, 0x00, 0x27, 0x80, 0x00, 0x03, 0xC8, 0x00, 0x2C, 0xF8, 0x00, 0x38, 0x38, 0x00, 0x20, 0x18, 0x00, 0x20, 0x08, 0x00, 0x00, 0x00}, /*"x", 88*/ + {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x30, 0x03, 0x00, 0x3C, 0x01, 0x00, 0x3F, 0x83, 0x00, 0x23, 0xEC, 0x00, 0x00, 0x70, 0x00, 0x23, 0x80, 0x00, 0x3C, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00}, /*"y", 89*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x08, 0x00, 0x20, 0x38, 0x00, 0x20, 0xF8, 0x00, 0x23, 0xE8, 0x00, 0x2F, 0x88, 0x00, 0x3E, 0x08, 0x00, 0x38, 0x08, 0x00, 0x20, 0x18, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00}, /*"z", 90*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x14, 0x00, 0x1F, 0xF7, 0xFC, 0x30, 0x00, 0x06, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"{", 91*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"|", 92*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x02, 0x30, 0x00, 0x06, 0x1F, 0xF7, 0xFC, 0x00, 0x14, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"}", 93*/ + {0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x10, 0x00, 0x00}, /*"~", 94*/ +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/src/basic/ssd1306/driver_ssd1306_interface.c b/app/src/basic/ssd1306/driver_ssd1306_interface.c new file mode 100644 index 0000000..b710232 --- /dev/null +++ b/app/src/basic/ssd1306/driver_ssd1306_interface.c @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2015 - present LibDriver All rights reserved + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * @file driver_ssd1306_interface_template.c + * @brief driver ssd1306 interface template source file + * @version 2.0.0 + * @author Shifeng Li + * @date 2021-03-30 + * + *

history

+ * + *
Date Version Author Description + *
2021/03/30 2.0 Shifeng Li format the code + *
2020/12/10 1.0 Shifeng Li first upload + *
+ */ + +#include "basic/ssd1306/driver_ssd1306_interface.h" + + +extern uint8_t SingleLeadECG_spi_init(void); +extern uint8_t SingleLeadECG_spi_deinit(void); +extern uint8_t SingleLeadECG_spi_write_cmd(uint8_t *buf, uint16_t len); +extern void SingleLeadECG_delay_ms(uint32_t ms); +extern void SingleLeadECG_debug_print(const char *const fmt, ...); +extern uint8_t SingleLeadECG_spi_cmd_data_gpio_init(void); +extern uint8_t SingleLeadECG_spi_cmd_data_gpio_deinit(void); +extern uint8_t SingleLeadECG_spi_cmd_data_gpio_write(uint8_t value); +extern uint8_t SingleLeadECG_reset_gpio_init(void); +extern uint8_t SingleLeadECG_reset_gpio_deinit(void); +extern uint8_t SingleLeadECG_reset_gpio_write(uint8_t value); + + +uint8_t ssd1306_interface_iic_init(void) { return 0; } +uint8_t ssd1306_interface_iic_deinit(void) { return 0; } +uint8_t ssd1306_interface_iic_write(uint8_t addr, uint8_t reg, uint8_t *buf, uint16_t len) { return 0; } + +uint8_t ssd1306_interface_spi_init(void) { return SingleLeadECG_spi_init(); } +uint8_t ssd1306_interface_spi_deinit(void) { return SingleLeadECG_spi_deinit(); } +uint8_t ssd1306_interface_spi_write_cmd(uint8_t *buf, uint16_t len) { return SingleLeadECG_spi_write_cmd(buf, len); } +void ssd1306_interface_delay_ms(uint32_t ms) { SingleLeadECG_delay_ms(ms); } +void ssd1306_interface_debug_print(const char *const fmt, ...) { SingleLeadECG_debug_print(fmt); } +uint8_t ssd1306_interface_spi_cmd_data_gpio_init(void) { return SingleLeadECG_spi_cmd_data_gpio_init(); } +uint8_t ssd1306_interface_spi_cmd_data_gpio_deinit(void) { return SingleLeadECG_spi_cmd_data_gpio_deinit(); } +uint8_t ssd1306_interface_spi_cmd_data_gpio_write(uint8_t value) { return SingleLeadECG_spi_cmd_data_gpio_write(value); } +uint8_t ssd1306_interface_reset_gpio_init(void) { return SingleLeadECG_reset_gpio_init(); } +uint8_t ssd1306_interface_reset_gpio_deinit(void) { return SingleLeadECG_reset_gpio_deinit(); } +uint8_t ssd1306_interface_reset_gpio_write(uint8_t value) { return SingleLeadECG_reset_gpio_write(value); } diff --git a/app/src/basic/ssd1306/driver_ssd1306_interface.h b/app/src/basic/ssd1306/driver_ssd1306_interface.h new file mode 100644 index 0000000..093ed1d --- /dev/null +++ b/app/src/basic/ssd1306/driver_ssd1306_interface.h @@ -0,0 +1,192 @@ +/** + * Copyright (c) 2015 - present LibDriver All rights reserved + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * @file driver_ssd1306_interface.h + * @brief driver ssd1306 interface header file + * @version 2.0.0 + * @author Shifeng Li + * @date 2021-03-30 + * + *

history

+ * + *
Date Version Author Description + *
2021/03/30 2.0 Shifeng Li format the code + *
2020/12/10 1.0 Shifeng Li first upload + *
+ */ + +#ifndef DRIVER_SSD1306_INTERFACE_H +#define DRIVER_SSD1306_INTERFACE_H + +#include "driver_ssd1306.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +/** + * @defgroup ssd1306_interface_driver ssd1306 interface driver function + * @brief ssd1306 interface driver modules + * @ingroup ssd1306_driver + * @{ + */ + +/** + * @brief interface iic bus init + * @return status code + * - 0 success + * - 1 iic init failed + * @note none + */ +uint8_t ssd1306_interface_iic_init(void); + +/** + * @brief interface iic bus deinit + * @return status code + * - 0 success + * - 1 iic deinit failed + * @note none + */ +uint8_t ssd1306_interface_iic_deinit(void); + +/** + * @brief interface iic bus write + * @param[in] addr is the iic device write address + * @param[in] reg is the iic register address + * @param[in] *buf points to a data buffer + * @param[in] len is the length of the data buffer + * @return status code + * - 0 success + * - 1 write failed + * @note none + */ +uint8_t ssd1306_interface_iic_write(uint8_t addr, uint8_t reg, uint8_t *buf, uint16_t len); + +/** + * @brief interface spi bus init + * @return status code + * - 0 success + * - 1 spi init failed + * @note none + */ +uint8_t ssd1306_interface_spi_init(void); + +/** + * @brief interface spi bus deinit + * @return status code + * - 0 success + * - 1 spi deinit failed + * @note none + */ +uint8_t ssd1306_interface_spi_deinit(void); + +/** + * @brief interface spi bus write + * @param[in] *buf points to a data buffer + * @param[in] len is the length of data buffer + * @return status code + * - 0 success + * - 1 write failed + * @note none + */ +uint8_t ssd1306_interface_spi_write_cmd(uint8_t *buf, uint16_t len); + +/** + * @brief interface delay ms + * @param[in] ms + * @note none + */ +void ssd1306_interface_delay_ms(uint32_t ms); + +/** + * @brief interface print format data + * @param[in] fmt is the format data + * @note none + */ +void ssd1306_interface_debug_print(const char *const fmt, ...); + +/** + * @brief interface command && data gpio init + * @return status code + * - 0 success + * - 1 gpio init failed + * @note none + */ +uint8_t ssd1306_interface_spi_cmd_data_gpio_init(void); + +/** + * @brief interface command && data gpio deinit + * @return status code + * - 0 success + * - 1 gpio deinit failed + * @note none + */ +uint8_t ssd1306_interface_spi_cmd_data_gpio_deinit(void); + +/** + * @brief interface command && data gpio write + * @param[in] value is the written value + * @return status code + * - 0 success + * - 1 gpio write failed + * @note none + */ +uint8_t ssd1306_interface_spi_cmd_data_gpio_write(uint8_t value); + +/** + * @brief interface reset gpio init + * @return status code + * - 0 success + * - 1 gpio init failed + * @note none + */ +uint8_t ssd1306_interface_reset_gpio_init(void); + +/** + * @brief interface reset gpio deinit + * @return status code + * - 0 success + * - 1 gpio deinit failed + * @note none + */ +uint8_t ssd1306_interface_reset_gpio_deinit(void); + +/** + * @brief interface reset gpio write + * @param[in] value is the written value + * @return status code + * - 0 success + * - 1 gpio write failed + * @note none + */ +uint8_t ssd1306_interface_reset_gpio_write(uint8_t value); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/src/one_conduction/one_conduction_board.c b/app/src/one_conduction/one_conduction_board.c index e69de29..cbeb1ba 100644 --- a/app/src/one_conduction/one_conduction_board.c +++ b/app/src/one_conduction/one_conduction_board.c @@ -0,0 +1,280 @@ +#include "one_conduction_board.h" + +#include "sys.h" +// +#include "app_timer.h" +#include "diskio_blkdev.h" +#include "ff.h" +#include "nrf_block_dev_sdc.h" +#include "nrf_delay.h" +#include "nrf_drv_pwm.h" +#include "nrf_drv_saadc.h" +#include "nrf_drv_twi.h" +#include "nrf_drv_wdt.h" +#include "nrf_gpio.h" + +#define SCREEN_SPI_INSTANCE 0 +#define SCREEN_RESET_PIN 20 +#define SCREEN_POWER_PIN 30 +#define SCREEN_A0PIN 31 +#define SCREEN_CS_PIN 29 +#define SCREEN_CLK_PIN 4 +#define SCREEN_MOSI_PIN 11 + +#define LED_GREEN_PIN 9 +#define LED_BLUE_PIN 10 + +#define ECG_NLOD_PIN 3 +#define ECG_PLOD_PIN 28 +#define ECG_ADC_PIN NRF_SAADC_INPUT_AIN2 +#define ECG_ADC_CHANNEL 0 // 不重复即可 + +#define BATTERY_ADC_PIN NRF_SAADC_INPUT_VDD +#define BATTERY_ADC_CHANNEL 1 // 不重复即可 + +#define EEPROM_I2C_SCL_M 15 // I2C SCL引脚 +#define EEPROM_I2C_SDA_M 17 // I2C SDA引脚 +#define EEPROM_I2C_INSTANCE 1 // I2C使用的硬件控制器ID + +/******************************************************************************* + * TOOLS * + *******************************************************************************/ + +static void znrf_gpio_cfg_output(uint32_t pin_number, nrf_gpio_pin_pull_t pull) { // + nrf_gpio_cfg(pin_number, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, pull, NRF_GPIO_PIN_S0S1, NRF_GPIO_PIN_NOSENSE); +} + +static int16_t adc_channel_read_val(uint16_t channel) { + nrf_saadc_value_t value; + ret_code_t err_code; + err_code = nrfx_saadc_sample_convert(channel, &value); + if (err_code != NRF_SUCCESS) { + ZLOGE("nrfx_saadc_sample_convert(%d) fail err_code:%d", channel, err_code); + return 0; + } + return value; +} + +/******************************************************************************* + * ADC * + *******************************************************************************/ +void SingleLeadECG_adc_module_init() { + nrf_drv_saadc_config_t adccfg = NRFX_SAADC_DEFAULT_CONFIG; + adccfg.resolution = NRF_SAADC_RESOLUTION_12BIT; // 4096 等于满采样率 + ZERROR_CHECK(nrf_drv_saadc_init(&adccfg, NULL)); +} + +/******************************************************************************* + * 蜂鸣器 * + *******************************************************************************/ +static nrf_drv_pwm_t m_beep_pwm0 = NRF_DRV_PWM_INSTANCE(0); +static nrf_pwm_values_individual_t m_beep_pwm0_seq_values = {0}; +static nrf_pwm_sequence_t const m_beep_pwm0_seq = { + .values.p_individual = &m_beep_pwm0_seq_values, + .length = NRF_PWM_VALUES_LENGTH(m_beep_pwm0_seq_values), + .repeats = 0, + .end_delay = 0, +}; +static nrf_drv_pwm_config_t const m_beep_pwm0_config0 = { + .output_pins = {11}, + .irq_priority = APP_IRQ_PRIORITY_LOWEST, + .base_clock = NRF_PWM_CLK_125kHz, + .count_mode = NRF_PWM_MODE_UP, + .top_value = 46, // 125kHz / 46 = 2.717k + .load_mode = NRF_PWM_LOAD_INDIVIDUAL, + .step_mode = NRF_PWM_STEP_AUTO, +}; +void SingleLeadECG_beep_init() { APP_ERROR_CHECK(nrfx_pwm_init(&m_beep_pwm0, &m_beep_pwm0_config0, NULL)); } +void SingleLeadECG_beep_set_state(bool state) { + if (state) { + m_beep_pwm0_seq_values.channel_0 = 23; // 设置占空比,数值最大不超过 top_value + nrfx_pwm_simple_playback(&m_beep_pwm0, &m_beep_pwm0_seq, 1, NRF_DRV_PWM_FLAG_LOOP); + } else { + nrfx_pwm_stop(&m_beep_pwm0, true); + } +} +/******************************************************************************* + * SCREEN * + *******************************************************************************/ + +typedef struct { + // BASIC IF + uint32_t reset_pin; + uint32_t power_pin; + uint32_t a0pin; // cmd/data + // SPI IF + uint32_t cs_pin; + uint32_t clk_pin; + uint32_t mosi_pin; + +} screen_handler_t; + +static screen_handler_t m_screen_handler = { + .reset_pin = SCREEN_RESET_PIN, + .power_pin = SCREEN_POWER_PIN, + .a0pin = SCREEN_A0PIN, + .cs_pin = SCREEN_CS_PIN, + .clk_pin = SCREEN_CLK_PIN, + .mosi_pin = SCREEN_MOSI_PIN, +}; +static const nrf_drv_spi_t m_screen_spi = NRF_DRV_SPI_INSTANCE(SCREEN_SPI_INSTANCE); /**< SPI instance. */ + +void SingleLeadECG_screen_init() { + znrf_gpio_cfg_output(SCREEN_RESET_PIN, NRF_GPIO_PIN_NOPULL); + znrf_gpio_cfg_output(SCREEN_POWER_PIN, NRF_GPIO_PIN_NOPULL); + znrf_gpio_cfg_output(SCREEN_A0PIN, NRF_GPIO_PIN_NOPULL); + + nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG; + spi_config.ss_pin = SCREEN_CS_PIN; // NRF_DRV_SPI_PIN_NOT_USED + spi_config.miso_pin = NRF_DRV_SPI_PIN_NOT_USED; + spi_config.mosi_pin = SCREEN_MOSI_PIN; + spi_config.sck_pin = SCREEN_CLK_PIN; + spi_config.frequency = NRF_DRV_SPI_FREQ_1M; + ZERROR_CHECK(nrf_drv_spi_init(&m_screen_spi, &spi_config, NULL, NULL)); +} + +void SingleLeadECG_screen_deinit() { + // TODO +} +uint8_t SingleLeadECG_spi_init(void) { return 0; } +uint8_t SingleLeadECG_spi_deinit(void) { return 0; } +uint8_t SingleLeadECG_spi_cmd_data_gpio_init(void) { return 0; } +uint8_t SingleLeadECG_spi_cmd_data_gpio_deinit(void) { return 0; } +void SingleLeadECG_debug_print(const char *const fmt, ...) {} +uint8_t SingleLeadECG_reset_gpio_init(void) { return 0; } +uint8_t SingleLeadECG_reset_gpio_deinit(void) { return 0; } +uint8_t SingleLeadECG_spi_write_cmd(uint8_t *buf, uint16_t len) { // + ZERROR_CHECK(nrf_drv_spi_transfer(&m_screen_spi, buf, len, NULL, 0)); + return 0; +} +void SingleLeadECG_delay_ms(uint32_t ms) { nrf_delay_ms(ms); } +uint8_t SingleLeadECG_spi_cmd_data_gpio_write(uint8_t value) { + if (value) { + nrf_gpio_pin_set(SCREEN_A0PIN); + } else { + nrf_gpio_pin_clear(SCREEN_A0PIN); + } + return 0; +} +uint8_t SingleLeadECG_reset_gpio_write(uint8_t value) { + if (value) { + nrf_gpio_pin_set(SCREEN_RESET_PIN); + } else { + nrf_gpio_pin_clear(SCREEN_RESET_PIN); + } + return 0; +} + +/******************************************************************************* + * LED * + *******************************************************************************/ +void SingleLeadECG_led_init() { + znrf_gpio_cfg_output(LED_GREEN_PIN, NRF_GPIO_PIN_NOPULL); + znrf_gpio_cfg_output(LED_BLUE_PIN, NRF_GPIO_PIN_NOPULL); +} +void SingleLeadECG_led_green_set_state(bool state) { + if (state) { + nrf_gpio_pin_set(LED_GREEN_PIN); + } else { + nrf_gpio_pin_clear(LED_GREEN_PIN); + } +} +void SingleLeadECG_led_blue_set_state(bool state) { + if (state) { + nrf_gpio_pin_set(LED_BLUE_PIN); + } else { + nrf_gpio_pin_clear(LED_BLUE_PIN); + } +} + +/******************************************************************************* + * ecg * + *******************************************************************************/ + +void SingleLeadECG_ecg_init() { + nrf_saadc_channel_config_t channel_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(ECG_ADC_PIN); + channel_config.acq_time = NRF_SAADC_ACQTIME_40US; + ZERROR_CHECK(nrfx_saadc_channel_init(ECG_ADC_CHANNEL, &channel_config)); + + nrf_gpio_cfg_sense_input(ECG_NLOD_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_NOSENSE); + nrf_gpio_cfg_sense_input(ECG_PLOD_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_NOSENSE); +} + +bool SingleLeadECG_ecg_nlod_get_connected_state() { return nrf_gpio_pin_read(ECG_NLOD_PIN) == 0; } +bool SingleLeadECG_ecg_plod_get_connected_state() { return nrf_gpio_pin_read(ECG_PLOD_PIN) == 0; } +int16_t SingleLeadECG_ecg_plod_get_ecg_val() { return adc_channel_read_val(ECG_ADC_CHANNEL); } + +/******************************************************************************* + * BATTERY * + *******************************************************************************/ +void SingleLeadECG_battery_init() { + nrf_saadc_channel_config_t channel_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(BATTERY_ADC_PIN); + channel_config.acq_time = NRF_SAADC_ACQTIME_10US; + ZERROR_CHECK(nrfx_saadc_channel_init(BATTERY_ADC_CHANNEL, &channel_config)); +} +int16_t SingleLeadECG_battery_get_adc_val() { + int16_t val = adc_channel_read_val(BATTERY_ADC_CHANNEL); + return val; +} + +/******************************************************************************* + * eeprom * + *******************************************************************************/ +static const nrf_drv_twi_t m_eeprom_twi_master = NRF_DRV_TWI_INSTANCE(EEPROM_I2C_INSTANCE); + +void SingleLeadECG_eeprom_init() { + const nrf_drv_twi_config_t config = { + .scl = EEPROM_I2C_SCL_M, + .sda = EEPROM_I2C_SDA_M, + .frequency = NRF_DRV_TWI_FREQ_100K, + .interrupt_priority = APP_IRQ_PRIORITY_HIGH, + .clear_bus_init = false, + }; + + ZERROR_CHECK(nrf_drv_twi_init(&m_eeprom_twi_master, &config, NULL, NULL)); + nrf_drv_twi_enable(&m_eeprom_twi_master); +} +static uint8_t eeprom_cache[EEPROM_PAGE + 2]; + +static void assign_i2c_add(uint32_t add, bool wr, uint8_t *i2cadd, uint8_t *memadd0, uint8_t *memadd1) { + // DEVICE SELECT + // bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 + // 1 0 1 0 E2 A17 A16 RW(W=0) + // + // PS: E2 参考原理图中的电平为0,所以bit3为0 + // + // MEM0 + // bit15 bit14 bit13 bit12 bit11 bit10 bit9 bit8 + // MEM1 + // bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 + // + + *i2cadd = 0xA0; + uint8_t a16a17 = (add >> 16) & 0x03; + *i2cadd |= a16a17 << 1; + + *i2cadd = wr ? *i2cadd & 0xFE : *i2cadd | 0x01; + + *memadd0 = add >> 8; + *memadd1 = add & 0xFF; +} + +void SingleLeadECG_eeprom_write(uint16_t page, uint8_t *data, uint16_t len) { // + uint32_t addr = page * EEPROM_PAGE; + len = len > EEPROM_PAGE ? EEPROM_PAGE : len; + uint8_t deviceSelect = 0; + + assign_i2c_add(addr, true, &deviceSelect, &eeprom_cache[0], &eeprom_cache[1]); + nrf_drv_twi_tx(&m_eeprom_twi_master, deviceSelect, eeprom_cache, len + 2, false); +} + +void SingleLeadECG_eeprom_read(uint32_t add, uint8_t *data, uint16_t len) { + uint8_t deviceSelect = 0; + uint8_t wadd[2] = {0}; + + assign_i2c_add(add, false, &deviceSelect, &wadd[0], &wadd[1]); + nrf_drv_twi_tx(&m_eeprom_twi_master, deviceSelect, wadd, 2, false); + + deviceSelect |= 0x01; // read + nrf_drv_twi_rx(&m_eeprom_twi_master, deviceSelect, data, len); +} diff --git a/app/src/one_conduction/one_conduction_board.h b/app/src/one_conduction/one_conduction_board.h index 95300f1..2f1cd12 100644 --- a/app/src/one_conduction/one_conduction_board.h +++ b/app/src/one_conduction/one_conduction_board.h @@ -1,4 +1,65 @@ #pragma once -#define VERSION 1 -#define MANUFACTURER_NAME "iflytop" -#define BLE_NAME "iflytop_test" \ No newline at end of file +#define VERSION 1 +#define MANUFACTURER_NAME "iflytop" +#define BLE_NAME "iflytop_test" + +/******************************************************************************* + * INCLUDE * + *******************************************************************************/ +#include + +#include "basic/ssd1306/driver_ssd1306_interface.h" + +/******************************************************************************* + * basic * + *******************************************************************************/ +void SingleLeadECG_adc_module_init(); + +/******************************************************************************* + * 蜂鸣器 * + *******************************************************************************/ +void SingleLeadECG_beep_init(); +void SingleLeadECG_beep_set_state(bool state); + +/******************************************************************************* + * EEPROM * + *******************************************************************************/ +/** + * + * PageSize 256byte + * + */ +#define EEPROM_PAGE 256 +void SingleLeadECG_eeprom_init(); +void SingleLeadECG_eeprom_write_page(uint16_t page, uint8_t* data, uint16_t len); +void SingleLeadECG_eeprom_read(uint32_t add, uint8_t* data, uint16_t len); + +/******************************************************************************* + * SCREEN * + *******************************************************************************/ + +void SingleLeadECG_screen_init(); +void SingleLeadECG_screen_deinit(); + +/******************************************************************************* + * LED * + *******************************************************************************/ +void SingleLeadECG_led_init(); +void SingleLeadECG_led_green_set_state(bool state); +void SingleLeadECG_led_blue_set_state(bool state); + +/******************************************************************************* + * ECG * + *******************************************************************************/ + +void SingleLeadECG_ecg_init(); +bool SingleLeadECG_ecg_nlod_get_connected_state(); +bool SingleLeadECG_ecg_plod_get_connected_state(); +int16_t SingleLeadECG_ecg_plod_get_ecg_val(); + +/******************************************************************************* + * BATTERY * + *******************************************************************************/ + +void SingleLeadECG_battery_init(); +int16_t SingleLeadECG_battery_get_adc_val(); \ No newline at end of file diff --git a/m24m02-dr.pdf b/m24m02-dr.pdf new file mode 100644 index 0000000000000000000000000000000000000000..67a6ec6f2cbbf8fae14353eef44919b44e7ad70f GIT binary patch literal 1024914 zcmeFYW3X;r(k-}coNe2-ZQHhO@3U>&wr$(CZF`@M)90Dpp!PSHFGw{XJp`D=jC;Bb~G`tf#T+Kw>L1dGI7Q?G%>TV?Opv zFy}=0TN9X3|M(f5zYv*W2$H2kCK}XL> z$H++Y$AiYn!`9iroyOLQ=&uNL{|Ld$P4_=C^5XyZ|DgW+Q{ew6$G;Bpf3W%wR{uHz z|GMXY-mCv$^{*rFuY3OIz54%v)&Ha*CboZghudESJ@@aInxavazr-;j=R{(6Y00u(9dpww+O^ob}P5y6!$imLb@jnQn`^K`4R4j3O zbkC*Q&^rHwC!e1H@HUIe2)L#B0@@(p$4Wohrv`K` z-Cg^K*>+iQoQUTb_S6`mW0%Xy-soG6C4Hn19KvTt^4WJ?_v7#v66O@RYUwY#5@lVH{ zGo$Wt%EuFKiF}Lg@0Ii_&AdoUQi>E%2knvt#JLEPww@oKY)zdqu67NWwDL_#?;7n} zo{ZR-62^lBua;dy&(*K|!Jnn|Y^a%&3&p>aa#kLdI(xW4ag8?5-QF7Mid*xuj3S8A zd3KNFStl)c6COprwRDLjHw&I-QFDUriVeKVX*8HWo#J=htkhGRd=ds6=&hdKl0z%Z z-U6YGsUE-7~ zgZ=WgYIqI}&CRi^H&Amv2;hBZgO$sRuX}wbx{l?9Id~Vpy*@ryH3&tC1L}de4++wp zU*<_bFam9qJUWmxB%;{4;>l$1>MysvF+jqOxsAdj=4An$=A%Z%?uIg!0WGr%PuviAfy

iE(d|j6tNrN*!eUjk zn*?~zCsz(D*rcvxe`Px>{(6=$%`D)#XFr3XEYB_OJz%*kd}+;5^2sf{F~$Pi|3<(k z=Hdlw!5RS&dOY$Sbcf(G0aXT7oGM`*=r`nc=s|_zf>Jfc%Box-sb>)&;u=mm0?zp* zkUxyzVuq2@1syT#XA0%m;{TkG&CYQLpHd3{22cIb8i^f{HHRDk>$05@C#_j2G}qzF z-PT2<*g5VPFK#S4#=b#?*@%eO`&s~^mMfl_yHY3ik$G^l3E>0Dp$qYQLM+ZehDP}C zUdzGl=$&(T0Bxa`Q0Uo}A}myioaX5Q#pbN`ksduL&HdzRf(tta-4+GrfxMZbUFx|c z*6XZ-K1%3yi=GXF8*GCnE`P_39rmsa=cl*ee+9N4%_6M~~GPP-%P80V|sI?%V= zDbgk&VJo3+&OIpM z-lKWyNMCy9{w96d398>V`nf-oNFUA!%6T!S34j+&E&zUaScCb7Ge|pur3sgt1DrH! z(+<{c$VkaXgB#4h1zID<;mJbBooR}X?)L5sv9&m>J5e-(v8bh0T9er$VlT^8-f7DC$D!z9>oUfz?x*4WxyE_T>A4jRcPuPwHy? z3|8*%!i3u?2=U$fu z5fEB>hxqnHNMH%J^bf$}?ghS?v9nN5lOsX_v^=R&p1pWsJZ5^uriemLP&ocEDS7h( ziOVI;L`BCZ*LboNVS#8lv%wz!&vUU)Wx_jiSm_raW;+11S;&TLlpq%Y{hX^z^j>Q- zb&fkGx-BCgQPr5cifecDUzjBqWUv%zth_91Y4&L`Sc!8Fq;79**ker`3kXw!fCK$5 zc1H(L#$D4{d$nxgmNJ+!(IDt_YjscT5Jes4{HjeA&*=>390T*Zm3s#CI-r@^MaTW7 z&4hTafrZ%jYXhMQtk48)@xa`m>{!4t>{I}Y+Ct{9Wlm$D_8cMd1uqMNZ4C$;6h01M zgH>#E)!KYcK zlfdN8BXOEsDft?f?E-g5dlzu)RXitkqRc)ijlQ^P(cqS-JFl%v+d@HLi6TMSTM6qn zLttr%lUXVVAStF-R9ACA-t!W9bwLWXu-yt_TlA>NRip)*VK*!+b}hy}X2@Dy3|zE% zls5#rP#A#7CX1l~Q-3VNC=U+p{P}LIw3%0@CmAcP)dKA>w^NL;$Fon@&zLW%FLf)6 zjjEa5MlKHY->9%1teB@J2ow#FYc%yC1<|YwjX$Jj;VTJ%Otk7i;RDu{7$`!?G@q zzJ}aD*Xj|#ikr7MwEn0{Bx*onB#cqPHl&WC6xY_5Me}UqWd(38cRlvT6eeFg0+38f z7Vc_RjuVCSYo=DBR!5%{R(%O}YVc~1QlzR)#>X7>l3&nH1}W(WXig+fZp2BwrxRbq zs2S4uux~A{LE}$xGR2d$bt1+P(FI2|r1t4o_mrP!QLUkyQ)Bu@{3U zk?Y)}{`rD)qXU;#qD(qn%9vO#(opHM?s|Ftw75-7)`K_c8cFg|;;fZN%epFa(xs<{ zxc?iE*NOh8r@sB`GyUkIA^MEcqV$%{q9&PFkBot^_!M2&h)WOax81JGmjQbmaZ+KJ z;+E~W%S`8_p|Qpz%V=FY%TEE6StXCecV8WMQl>m}iN|>95K4r8*BiWq3^&{2)!9iW}RbWw{n2v$?M>V^(WT zSb!xYjPyFym^V^ot-gaY3C5@A@+V@KB{+kb9prB}-B`tmS`NU6^!gT6+{&DVwKard z%B$u=etDBc>?c`(6t%qY@=i{<^72lwI8G*zW!$%LCah$LnFUnEtV0g@Y^ngu*oUz& zR)uTmU8VKdXs&+t#MzFfKKrgYtKmC1310ciFn18E)?$Zk4@+dWzWa2>$pAYXacPXO zuiB)>gvnu8ZrOHY%X7 z3K}v-L{N?pFEi#;JZxn?QoO8I-8y={QJHN>s3j^?r`WJ={rlBN+Bnqcpd~iEd7Ys{ z9vBv(B!^cRqdSbz6OPH1;fi%R#oJk14w_l2N;Onk6HY-9E2>KzQFEj+Cz4($U|_| zw9;@HMNBTBTSw4aN0$Eh;fvXzSA~^e5T-6IT+}<;(r{T$)8{tb#r?1Na5$|#uT;yE zwLKj1&U4xPdhq>jR-Z{^kGM0SE+t@{P`7qJxAqKSWj#;AuGoZ|_uIX0EE_+!&J1bg zP{JYG!w)i~D~PUG+TKH6l9MYi_uCkuzGOrz%pSrWyLzSuTH>{SuhrqWyiFh49(={> z?Toy}%{`x|Y8*G1akguP>OG(I?#9u-kNZAa{ajuUJFP5Td`37{L2fVjU9}BvFF(5U z;APkbKhm$Vc>r!F|BNuVn?O73OnW}k=edBlr`JwwU386ZFX&yh48I-R^-OQCFz$T8 z9&bZmiC8-!cj&IH8^2~=4F2|n!JRKBbqnma^G_VW9kunpGS2>);p@(q__w7bcQ=Oa z`NaPMi{J(eMl z+L^N_>++&TA;g~ES?9OD`-8@h-gTL~o%HGT&QOaed3(;wCIHFj71p<$*h?0io9Llm zbb4TZvdpe{U2Ns9*gs7`cjAL|3hs0*+^A>ba4Z+5{>&ypY+C==@7Agww91FQq#q2A zrJ1R-y5sd)@H<*I4^sCw(+)j{W6}3*zW3``ZVq|+aNX6MXg{67^>e#mCw40t0=uO; zm@fQH-sNV><$gPu`=iqXB84`5+Z6ah^%3Sx8`fiW!;58hmE{$3r*=2p^>l^Olka{W zt|ob{MHOubueEt2eIBbs6#tqT==4|=hgGnvNxAj9rUv1JB=|jZMM7=iTHn`-zE+T< z*rpy#+Y|c!o<=p%7Ny4_vYGP3LaS=qlW0m+bJI}g$Im6y%PWN=(=vn;Xb1nZE88?W zo0%RL=SUZ_(}WLTt*Y_g1(=O*2W5|_R2^yWtJd{1te3602s%lbNdP&yAdg2iB~6-l zFll(L>azo%7yj+KCb!JoH5@!S6E!?Jl!2geiVU_R5^$+N@=c>FGb;x5p_g?{iU#G% z$}|ek4P`LORtwY>AkCwINA2LNlG)j<^`!DXQIn#I3YUiu?P_zMrrhQ-lnAB2XcJc4 z#$PFfiqNHC^q+vcFUMqayr`yoLZImP-tO`+P1k*G^=M6z7(9Bn0mS!%@1hzkOcl^E zh=iZD>Vp};rc!FJE8A4aAf=&uGjwRe>u+xE-1Cqh28%3EXS4SK#OcjB?O3Q^@E5!4 zT~mWsoV*a2lbqYz9^**aNFFGv5dZaTmcQ%#?d2nrt1b;uyrBZ0fsV#P&JUB{fa%wm zj=QdgZ4>}$LtZzDLN5Cb)K%Q*EmLgh$TRoi;yuzE)>j7N^_~=ry;x>1!mF7Vz@ySr zE!pS#U=cdYj1JdFu>}i6YuUX;gFnG9tgj>ZhY`Y