├── LICENSE ├── README.md ├── demo.jpg ├── examples ├── Unicode_demo │ ├── DejaVuSansMono_Bold14pt8b.h │ └── Unicode_demo.ino ├── co2_uno_epd │ ├── Roboto_Black_28.h │ └── co2_uno_epd.ino ├── epd_test │ ├── Roboto_Black_40.h │ └── epd_test.ino ├── epd_test_213_bwr │ └── epd_test_213_bwr.ino ├── multi_oled_demo │ └── multi_oled_demo.ino ├── obd_class_demo │ └── obd_class_demo.ino ├── obd_cmd_demo │ └── obd_cmd_demo.ino ├── oled_gfx_demo │ └── oled_gfx_demo.ino ├── onebit_lcd_test │ └── onebit_lcd_test.ino ├── pico_oled_13_demo │ └── pico_oled_13_demo.ino ├── prop_font_demo │ ├── FreeSerif12pt7b.h │ └── prop_font_demo.ino ├── sharp_memory_lcd │ └── sharp_memory_lcd.ino ├── simple_demo │ └── simple_demo.ino ├── simple_demo_avr │ └── simple_demo_avr.ino ├── tiff_on_avr │ ├── bart_1bpp.h │ ├── tiff_on_avr.ino │ └── uno_bw.h ├── uc1609_test │ ├── uc1609.h │ └── uc1609_test.ino └── virtual_display │ └── virtual_display.ino ├── fontconvert ├── Makefile ├── README.txt └── main.c ├── fonts_opt.jpg ├── library.properties ├── linux ├── Makefile ├── OLED_demo │ ├── Makefile │ └── main.c ├── README.txt ├── Sharp_LCD │ ├── Makefile │ └── main.c ├── epd_cpp_demo │ ├── Makefile │ └── main.cpp ├── epd_demo │ ├── Makefile │ ├── Roboto_Black_28.h │ └── main.c ├── gif_1_bus_2_oleds │ ├── Makefile │ ├── main.c │ └── running_256_64.h ├── obd.c ├── sharp_fast_gif │ ├── Makefile │ ├── main.c │ └── pattern_400x240.h ├── sharp_lcd_gif │ ├── Makefile │ ├── main.c │ └── pattern_400x240.h ├── spi_demo │ ├── Makefile │ └── main.c └── virtual_disp │ ├── Makefile │ ├── main.c │ └── notes.h ├── notes.txt ├── sharp_lcd.jpg └── src ├── OneBitDisplay.cpp ├── OneBitDisplay.h ├── obd.inl ├── obd_gfx.inl ├── obd_io.inl └── obd_stub.inl /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 BitBank Software, Inc. All rights reserved. 2 | 3 | Apache License 4 | Version 2.0, January 2004 5 | http://www.apache.org/licenses/ 6 | 7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8 | 9 | 1. Definitions. 10 | 11 | "License" shall mean the terms and conditions for use, reproduction, 12 | and distribution as defined by Sections 1 through 9 of this document. 13 | 14 | "Licensor" shall mean the copyright owner or entity authorized by 15 | the copyright owner that is granting the License. 16 | 17 | "Legal Entity" shall mean the union of the acting entity and all 18 | other entities that control, are controlled by, or are under common 19 | control with that entity. For the purposes of this definition, 20 | "control" means (i) the power, direct or indirect, to cause the 21 | direction or management of such entity, whether by contract or 22 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 23 | outstanding shares, or (iii) beneficial ownership of such entity. 24 | 25 | "You" (or "Your") shall mean an individual or Legal Entity 26 | exercising permissions granted by this License. 27 | 28 | "Source" form shall mean the preferred form for making modifications, 29 | including but not limited to software source code, documentation 30 | source, and configuration files. 31 | 32 | "Object" form shall mean any form resulting from mechanical 33 | transformation or translation of a Source form, including but 34 | not limited to compiled object code, generated documentation, 35 | and conversions to other media types. 36 | 37 | "Work" shall mean the work of authorship, whether in Source or 38 | Object form, made available under the License, as indicated by a 39 | copyright notice that is included in or attached to the work 40 | (an example is provided in the Appendix below). 41 | 42 | "Derivative Works" shall mean any work, whether in Source or Object 43 | form, that is based on (or derived from) the Work and for which the 44 | editorial revisions, annotations, elaborations, or other modifications 45 | represent, as a whole, an original work of authorship. For the purposes 46 | of this License, Derivative Works shall not include works that remain 47 | separable from, or merely link (or bind by name) to the interfaces of, 48 | the Work and Derivative Works thereof. 49 | 50 | "Contribution" shall mean any work of authorship, including 51 | the original version of the Work and any modifications or additions 52 | to that Work or Derivative Works thereof, that is intentionally 53 | submitted to Licensor for inclusion in the Work by the copyright owner 54 | or by an individual or Legal Entity authorized to submit on behalf of 55 | the copyright owner. For the purposes of this definition, "submitted" 56 | means any form of electronic, verbal, or written communication sent 57 | to the Licensor or its representatives, including but not limited to 58 | communication on electronic mailing lists, source code control systems, 59 | and issue tracking systems that are managed by, or on behalf of, the 60 | Licensor for the purpose of discussing and improving the Work, but 61 | excluding communication that is conspicuously marked or otherwise 62 | designated in writing by the copyright owner as "Not a Contribution." 63 | 64 | "Contributor" shall mean Licensor and any individual or Legal Entity 65 | on behalf of whom a Contribution has been received by Licensor and 66 | subsequently incorporated within the Work. 67 | 68 | 2. Grant of Copyright License. Subject to the terms and conditions of 69 | this License, each Contributor hereby grants to You a perpetual, 70 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 71 | copyright license to reproduce, prepare Derivative Works of, 72 | publicly display, publicly perform, sublicense, and distribute the 73 | Work and such Derivative Works in Source or Object form. 74 | 75 | 3. Grant of Patent License. Subject to the terms and conditions of 76 | this License, each Contributor hereby grants to You a perpetual, 77 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 78 | (except as stated in this section) patent license to make, have made, 79 | use, offer to sell, sell, import, and otherwise transfer the Work, 80 | where such license applies only to those patent claims licensable 81 | by such Contributor that are necessarily infringed by their 82 | Contribution(s) alone or by combination of their Contribution(s) 83 | with the Work to which such Contribution(s) was submitted. If You 84 | institute patent litigation against any entity (including a 85 | cross-claim or counterclaim in a lawsuit) alleging that the Work 86 | or a Contribution incorporated within the Work constitutes direct 87 | or contributory patent infringement, then any patent licenses 88 | granted to You under this License for that Work shall terminate 89 | as of the date such litigation is filed. 90 | 91 | 4. Redistribution. You may reproduce and distribute copies of the 92 | Work or Derivative Works thereof in any medium, with or without 93 | modifications, and in Source or Object form, provided that You 94 | meet the following conditions: 95 | 96 | (a) You must give any other recipients of the Work or 97 | Derivative Works a copy of this License; and 98 | 99 | (b) You must cause any modified files to carry prominent notices 100 | stating that You changed the files; and 101 | 102 | (c) You must retain, in the Source form of any Derivative Works 103 | that You distribute, all copyright, patent, trademark, and 104 | attribution notices from the Source form of the Work, 105 | excluding those notices that do not pertain to any part of 106 | the Derivative Works; and 107 | 108 | (d) If the Work includes a "NOTICE" text file as part of its 109 | distribution, then any Derivative Works that You distribute must 110 | include a readable copy of the attribution notices contained 111 | within such NOTICE file, excluding those notices that do not 112 | pertain to any part of the Derivative Works, in at least one 113 | of the following places: within a NOTICE text file distributed 114 | as part of the Derivative Works; within the Source form or 115 | documentation, if provided along with the Derivative Works; or, 116 | within a display generated by the Derivative Works, if and 117 | wherever such third-party notices normally appear. The contents 118 | of the NOTICE file are for informational purposes only and 119 | do not modify the License. You may add Your own attribution 120 | notices within Derivative Works that You distribute, alongside 121 | or as an addendum to the NOTICE text from the Work, provided 122 | that such additional attribution notices cannot be construed 123 | as modifying the License. 124 | 125 | You may add Your own copyright statement to Your modifications and 126 | may provide additional or different license terms and conditions 127 | for use, reproduction, or distribution of Your modifications, or 128 | for any such Derivative Works as a whole, provided Your use, 129 | reproduction, and distribution of the Work otherwise complies with 130 | the conditions stated in this License. 131 | 132 | 5. Submission of Contributions. Unless You explicitly state otherwise, 133 | any Contribution intentionally submitted for inclusion in the Work 134 | by You to the Licensor shall be under the terms and conditions of 135 | this License, without any additional terms or conditions. 136 | Notwithstanding the above, nothing herein shall supersede or modify 137 | the terms of any separate license agreement you may have executed 138 | with Licensor regarding such Contributions. 139 | 140 | 6. Trademarks. This License does not grant permission to use the trade 141 | names, trademarks, service marks, or product names of the Licensor, 142 | except as required for reasonable and customary use in describing the 143 | origin of the Work and reproducing the content of the NOTICE file. 144 | 145 | 7. Disclaimer of Warranty. Unless required by applicable law or 146 | agreed to in writing, Licensor provides the Work (and each 147 | Contributor provides its Contributions) on an "AS IS" BASIS, 148 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 149 | implied, including, without limitation, any warranties or conditions 150 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 151 | PARTICULAR PURPOSE. You are solely responsible for determining the 152 | appropriateness of using or redistributing the Work and assume any 153 | risks associated with Your exercise of permissions under this License. 154 | 155 | 8. Limitation of Liability. In no event and under no legal theory, 156 | whether in tort (including negligence), contract, or otherwise, 157 | unless required by applicable law (such as deliberate and grossly 158 | negligent acts) or agreed to in writing, shall any Contributor be 159 | liable to You for damages, including any direct, indirect, special, 160 | incidental, or consequential damages of any character arising as a 161 | result of this License or out of the use or inability to use the 162 | Work (including but not limited to damages for loss of goodwill, 163 | work stoppage, computer failure or malfunction, or any and all 164 | other commercial damages or losses), even if such Contributor 165 | has been advised of the possibility of such damages. 166 | 167 | 9. Accepting Warranty or Additional Liability. While redistributing 168 | the Work or Derivative Works thereof, You may choose to offer, 169 | and charge a fee for, acceptance of support, warranty, indemnity, 170 | or other liability obligations and/or rights consistent with this 171 | License. However, in accepting such obligations, You may act only 172 | on Your own behalf and on Your sole responsibility, not on behalf 173 | of any other Contributor, and only if You agree to indemnify, 174 | defend, and hold each Contributor harmless for any liability 175 | incurred by, or claims asserted against, such Contributor by reason 176 | of your accepting any such warranty or additional liability. 177 | 178 | END OF TERMS AND CONDITIONS 179 | 180 | APPENDIX: How to apply the Apache License to your work. 181 | 182 | To apply the Apache License to your work, attach the following 183 | boilerplate notice, with the fields enclosed by brackets "[]" 184 | replaced with your own identifying information. (Don't include 185 | the brackets!) The text should be enclosed in the appropriate 186 | comment syntax for the file format. We also recommend that a 187 | file or class name and description of purpose be included on the 188 | same "printed page" as the copyright notice for easier 189 | identification within third-party archives. 190 | 191 | Copyright [yyyy] [name of copyright owner] 192 | 193 | Licensed under the Apache License, Version 2.0 (the "License"); 194 | you may not use this file except in compliance with the License. 195 | You may obtain a copy of the License at 196 | 197 | http://www.apache.org/licenses/LICENSE-2.0 198 | 199 | Unless required by applicable law or agreed to in writing, software 200 | distributed under the License is distributed on an "AS IS" BASIS, 201 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 202 | See the License for the specific language governing permissions and 203 | limitations under the License. 204 | 205 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | OneBitDisplay (1-bpp OLED/LCD library)
2 | ----------------------------------- 3 | Project started 3/23/2020
4 | Copyright (c) 2020 BitBank Software, Inc.
5 | Written by Larry Bank
6 | bitbank@pobox.com
7 |
8 | ![OneBitDisplay](/demo.jpg?raw=true "OneBitDisplay") 9 |
10 | The purpose of this code is to easily control monochrome (1-bit per pixel) OLED and LCD displays. The displays can be connected to the traditional I2C or SPI bus, or you can use GPIO pins to bit bang the signals.
11 |
12 | On AVR microcontrollers, there is an optimized option to speed up access to the GPIO pins to allow speeds which match or exceed normal I2C speeds. The pins are numbered with the Port letter as the first digit followed by the bit number. For example, To use bit 0 of Port B, you would reference pin number 0xb0.
13 |
14 | Includes the unique feature that the I2C init function can optionally detect the display address (0x3C or 0x3D) and the controller type (SSD1306, SH1106 or SH1107).
15 |
16 | I try to support as many OLEDs as I can. I was able to justify buying a bunch 17 | of different sized SSD1306 displays because they're around $2 each. A generous patron 18 | donated money so that I could purchase Pimoroni's 128x128 OLED and add support for it. 19 | It uses the SH1107 controller and behaves very similarly to the SH1106. 20 |
21 | 22 | Features:
23 | ---------
24 | - C API and C++ wrapper class which mimics the Adafruit_GFX API 25 | - Supports any number of simultaneous displays of any type (mix and match)
26 | - Optionally detect the display address and type (I2C only)
27 | - Supports 72x40, 96x16, 64x32, 128x32, 128x64, 64x128 (SH1107), 128x128 (SH1107) and 132x64 (SH1106) OLED display sizes
28 | - Supports 96x68 HX1230, 84x48 Nokia 5110 and 128x64 ST7567/UC1701 mono LCDs
29 | - Supports 144x168 and 400x240 Sharp Memory LCDs
30 | - Supports the ST7302 low power LCD (250x122, 2.13") 31 | - *NEW* supports a few popular epd (e-ink) panels 32 | - Virtual displays of any size which can be drawn across multiple physical displays 33 | - Flexible copy function can convert the internal pixel format to any output format and orientation 34 | - Drive displays from I2C, SPI or any GPIO pins (virtual I2C/SPI)
35 | - Includes 5 sizes of fixed fonts (6x8, 8x8, 12x16, 16x16, 16x32)
36 | - Text drawing at any fractional scale (e.g. 1.25x), and any of 4 directions/rotations
37 | - Can use Adafruit_GFX format bitmap fonts (proportional and fixed)
38 | - Deferred rendering allows preparing a back buffer, then displaying it (usually faster)
39 | - Text scrolling features (vertical and horizontal)
40 | - Text cursor position with optional line wrap
41 | - A function to load a Windows BMP file
42 | - Pixel drawing on SH1106/7 without needing backing RAM
43 | - Optimized Bresenham line drawing
44 | - Optimized Bresenham outline and filled ellipse drawing
45 | - Optimized outline and filled rectangle drawing
46 | - Optional backing RAM (needed for some text and drawing functions)
47 | - 16x16 Tile/Sprite drawing at any angle.
48 | - Run full frame animations at high frame rates with a simple API
49 |
50 | This code depends on the BitBang_I2C library. You can download it here:
51 | https://github.com/bitbank2/BitBang_I2C 52 |
53 | See the Wiki for help getting started
54 | https://github.com/bitbank2/OneBitDisplay/wiki
55 |
56 | 57 | ![Fonts](/fonts_opt.jpg?raw=true "fonts") 58 | A few words about fonts
59 | -----------------------
60 | 61 | The library includes 3 fixed fonts (6x8, 8x8 and 16x32). The 16x32 font is disabled when compiling for AVR targets (e.g. Arduino Uno) to save FLASH program space. The other 2 fonts offer 2x stretched versions (12x16 from 6x8 and 16x16 from 8x8). A simple smoothing algorithm is applied to the stretched 6x8 font to make it look better. In the photo above are the first 4 font sizes shown on a 128x64 yellow OLED display. Only 96 ASCII characters are defined per font to save space. To use more elaborate fonts with more extensive character support, use Adafruit_GFX format bitmap fonts with the `obdWriteStringCustom()` function.
62 | 63 | ![Sharp Memory LCD](/sharp_lcd.jpg?raw=true "Sharp_LCD") 64 | Sharp Memory LCD Support
65 | ------------------------
66 | New - support for the Sharp 144x168 and 400x240 memory LCDs. These are a different type of LCD that have a high refresh rate and low power usage. They cost quite a bit more than normal LCDs. They require a memory back buffer to use the drawing functions due to the way data is written to them one line at a time. I've also added a specific function if you would like to skip the back buffer - `obdWriteLCDLine()`. It allows you to write a single line of pixels without needing any additional memory. Please see the Wiki for more details.
67 | 68 | Instructions for use:
69 | ---------------------
70 | Start by initializing the library. Either using hardware I2C, bit-banged I2C or SPI to talk to the display. For I2C, the 71 | address of the display will be detected automatically (either 0x3c or 0x3d) or you can specify it. The typical MCU only allows setting the I2C speed up to 400Khz, but the SSD1306 displays can handle a much faster signal. With the bit-bang code, you can usually specify a stable 800Khz clock and with Cortex-M0 targets, the hardware I2C can be told to be almost any speed, but the displays I've tested tend to stop working beyond 1.6Mhz.
72 |
73 | After initializing the display you can begin drawing text or graphics on it. The final parameter of all of the drawing functions is a render flag. When true, the graphics will be sent to the internal backing buffer (when available) and sent to the display. You optionally pass the library a backing buffer (if your MCU has enough RAM) with the obdSetBackBuffer() function. When the render flag is false, the graphics will only be drawn into the internal buffer. Once you're ready to send the pixels to the display, call obdDumpBuffer(NULL) and it will copy the internal buffer in its entirety to the display.
74 |
75 | The text drawing function now has a scroll offset parameter. This tells it how many pixels of the text to skip before drawing the text at the given destination coordinates. For example, if you pass a value of 20 for the scroll offset and are using an 8-pixel wide font (FONT_8x8), the first two and a half characters will not be drawn; the second half of the third and subsequent characters will be drawn starting at the x/y you specified. This allows you to create a scrolling text effect by repeatedly calling the oledWriteString() function with progressively larger scroll offset values to make the text scroll from right to left.
76 |
77 | 78 | If you find this code useful, please consider sending a donation or becomming a Github sponsor. 79 | 80 | [![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=SR4F44J2UR8S4) 81 | 82 | -------------------------------------------------------------------------------- /demo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitbank2/OneBitDisplay/5c5e1b9c2ebd08a63e66c39460514a9d811bb921/demo.jpg -------------------------------------------------------------------------------- /examples/Unicode_demo/Unicode_demo.ino: -------------------------------------------------------------------------------- 1 | // 2 | // Unicode character demo 3 | // 4 | // The purpose of this demo is to show how to use Unicode 5 | // characters directly in your sketches with no hassles 6 | // OneBitDisplay supports using 8-bit values to display 7 | // TrueType font glyphs that have been converted to 8 | // bitmap form. This limits the possible characters that 9 | // can be displayed since Unicode is a 16-bit code. The 10 | // workaround created by Microsoft many years ago was to 11 | // select the most used characters for Western languages 12 | // and place them in a set they called codepage 1252. This 13 | // set includes accented characters and symbols in the 14 | // range 128-255. These map to Unicode values up to 2300. 15 | // OneBitDisplay now allows you to generate bitmap fonts 16 | // with this mapping (use the fontconvert tool) and the 17 | // UTF-8 multi-byte characters typed into your text editor 18 | // get converted on the fly to the codepage 1252 range. 19 | // This works for most situations except Asian and middle-East 20 | // languages. 21 | // 22 | #include 23 | #include "DejaVuSansMono_Bold14pt8b.h" 24 | ONE_BIT_DISPLAY obd; 25 | 26 | void setup() 27 | { 28 | obd.I2Cbegin(OLED_128x64); 29 | obd.allocBuffer(); // we need a back buffer for precise vertical placement on this OLED 30 | obd.fillScreen(OBD_WHITE); 31 | obd.setFreeFont(&DejaVuSansMono_Bold14pt8b); 32 | obd.setCursor(0, 22); // the character baseline is the Y position for TrueType fonts 33 | obd.println("Está a"); // Use UTF-8 strings directly in your code 34 | obd.println("começar!"); // and the characters will map internally to codepage 1252 35 | obd.display(); // show the buffer on the physical display 36 | } 37 | 38 | void loop() 39 | { 40 | 41 | } 42 | -------------------------------------------------------------------------------- /examples/co2_uno_epd/co2_uno_epd.ino: -------------------------------------------------------------------------------- 1 | // 2 | // OneBitDisplay EPD (e-ink) demo sketch 3 | // Written by Larry Bank 10/10/2022 4 | // 5 | // This program shows how to use epd panels 6 | // with the OneBitDisplay library. The general idea 7 | // is that it doesn't support "immediate" mode with e-ink. 8 | // You'll need to allocate a buffer to hold the pixel 9 | // data, draw on it, then dump it all at once to the panel 10 | // as a full update (display) or partial (displayPartial). 11 | // If your MCU doesn't have enough RAM to hold the framebuffer 12 | // then you can use the 'zero buffer' mode as shown below. 13 | // The orientation and drawing functions are more limited, 14 | // but an MCU with constrained resources can still display 15 | // attractive content. 16 | // 17 | #include 18 | #include 19 | #include "Roboto_Black_28.h" 20 | 21 | ONE_BIT_DISPLAY lcd; 22 | SCD41 mySensor; 23 | 24 | // Define both of these to be -1 for default I2C pins 25 | #define SDA_PIN -1 26 | #define SCL_PIN -1 27 | #define BITBANG false 28 | 29 | #if defined(ARDUINO_AVR_UNO) 30 | #define EPD_FREQ 2000000 31 | #define EPD_CS 10 32 | #define EPD_DC 9 33 | #define EPD_BUSY 7 34 | #define EPD_RES 8 35 | #define EPD_MOSI -1 36 | #define EPD_SCK -1 37 | #define POWER_ENABLE -1 38 | #define EPD_TYPE EPD213_122x250 39 | #endif 40 | void setup() 41 | { 42 | lcd.setSPIPins(EPD_CS, EPD_MOSI, EPD_SCK, EPD_DC, EPD_RES, EPD_BUSY); 43 | lcd.SPIbegin(EPD_TYPE, EPD_FREQ); 44 | lcd.setRotation(90); 45 | if (mySensor.init(SDA_PIN, SCL_PIN, BITBANG, 100000) == SCD41_SUCCESS) 46 | { 47 | mySensor.start(); // start sampling mode 48 | } else { // can't find the sensor, stop 49 | lcd.fillScreen(OBD_WHITE); 50 | lcd.drawString("SCD41 not found!",0,0); 51 | lcd.drawString("Halted...", 0, 8); 52 | lcd.display(); 53 | while (1) {}; 54 | } 55 | } /* setup() */ 56 | 57 | void loop() { 58 | char szTemp[32]; 59 | 60 | mySensor.getSample(); 61 | lcd.fillScreen(OBD_WHITE); // 0 for EPDs is white (for OneBitDisplay) 62 | lcd.setTextColor(OBD_BLACK); 63 | lcd.setFont(FONT_12x16); 64 | lcd.drawString("2.13 250x122 AVR test",0,0); 65 | lcd.setFreeFont(&Roboto_Black_28); 66 | // Display CO2 value 67 | sprintf(szTemp, "CO2: %dppm", mySensor.co2()); 68 | lcd.drawString(szTemp, 0, 48); 69 | 70 | // Display temperature 71 | sprintf(szTemp, "Temperature: %dC", mySensor.temperature()); 72 | lcd.drawString(szTemp, 0, 88); 73 | 74 | // Display humidity 75 | sprintf(szTemp, "Humidity: %d%%", mySensor.humidity()); 76 | lcd.drawString(szTemp, 0, 122); 77 | 78 | // Tell EPD to do a full refresh 79 | lcd.display(); 80 | delay(30000); // get a new sample every 30 seconds 81 | } 82 | -------------------------------------------------------------------------------- /examples/epd_test/epd_test.ino: -------------------------------------------------------------------------------- 1 | // 2 | // OneBitDisplay EPD (e-ink) demo sketch 3 | // Written by Larry Bank 7/10/2022 4 | // 5 | // This program shows how to use epd panels 6 | // with the OneBitDisplay library. The general idea 7 | // is that it doesn't support "immediate" mode with e-ink. 8 | // You'll need to allocate a buffer to hold the pixel 9 | // data, draw on it, then dump it all at once to the panel 10 | // as a full update (display) or partial (displayPartial). 11 | // This demo draws some text using the built-in fonts and 12 | // a custom font in Adafruit_GFX format 13 | // 14 | // The target hardware for this demo is the Pimoroni Badger2040 15 | // A RPI Pico MCU with a UC8151 2.9" 128x296 1-bpp epd 16 | // 17 | #include 18 | #include "Roboto_Black_40.h" 19 | 20 | ONE_BIT_DISPLAY lcd; 21 | 22 | #define BADGER_FREQ 12000000 23 | #define BADGER_CS 17 24 | #define BADGER_BUSY -1 25 | #define BADGER_RES 21 26 | #define BADGER_DC 20 27 | #define BADGER_MOSI 19 28 | #define BADGER_SCK 18 29 | #define BADGER_BATT 29 30 | 31 | void setup() { 32 | // Initialize the library by telling it how the display is connected 33 | lcd.setSPIPins(BADGER_CS, -1, -1, BADGER_DC, BADGER_RES, BADGER_BUSY); 34 | lcd.SPIbegin(EPD29_128x296, BADGER_FREQ); // 12Mhz is fast enough 35 | 36 | // Set the orientation to draw in the direction we want 37 | lcd.setRotation(90); // the panel is actually 128 wide by 296 tall, but oriented 90 right 38 | lcd.allocBuffer(); // allocate a back buffer and keep it internal to the class 39 | lcd.fillScreen(OBD_WHITE); // 0 for EPDs is white (for OneBitDisplay) 40 | lcd.setFont(FONT_12x16); // use the internal stretched/smoothed font 41 | lcd.print("This was a full update"); 42 | lcd.display(); // do a full update 43 | for (int i=24; i<120; i += 32) { 44 | lcd.fillCircle(i, i, 8, 1); 45 | lcd.displayFast(); // draw a ball and show intermediate results with a partial update 46 | } 47 | lcd.setCursor(0, 112); 48 | lcd.print("then a partial update"); 49 | lcd.displayFast(); // final partial update 50 | delay(4000); 51 | lcd.fillScreen(OBD_WHITE); 52 | lcd.setFreeFont(&Roboto_Black_40); 53 | lcd.setCursor(0,40); 54 | lcd.println("Gratuitous"); 55 | lcd.println("pretty font"); 56 | lcd.setFont(FONT_12x16); 57 | lcd.setCursor(0,112); 58 | lcd.println("Finished"); 59 | lcd.display(); // show final screen with a full update 60 | } 61 | 62 | void loop() { 63 | // nothing going on here 64 | } 65 | -------------------------------------------------------------------------------- /examples/epd_test_213_bwr/epd_test_213_bwr.ino: -------------------------------------------------------------------------------- 1 | // 2 | // OneBitDisplay BWR EPD (e-ink) demo sketch 3 | // Written by Larry Bank 7/10/2022 4 | // edit by Aaron Christophel ATC1441 20/11/2022 5 | // 6 | // This program shows how to use epd panels 7 | // with the OneBitDisplay library. The general idea 8 | // is that it doesn't support "immediate" mode with e-ink. 9 | // You'll need to allocate a buffer to hold the pixel 10 | // data, draw on it, then dump it all at once to the panel 11 | // as a full update (display) or partial (displayPartial). 12 | // This demo draws some text using the built-in fonts and 13 | // a custom font in Adafruit_GFX format 14 | // 15 | 16 | #include 17 | 18 | ONE_BIT_DISPLAY lcd; 19 | 20 | #define EPD_FREQ 12000000 21 | #define EPD_CS 5 22 | #define EPD_BUSY 4 23 | #define EPD_RES 16 24 | #define EPD_DC 17 25 | #define EPD_MOSI 23 26 | #define EPD_SCK 18 27 | 28 | void setup() { 29 | // Initialize the library by telling it how the display is connected 30 | lcd.setSPIPins(EPD_CS, -1, -1, EPD_DC, EPD_RES, EPD_BUSY); 31 | lcd.SPIbegin(EPD213R_104x212_d, EPD_FREQ); // 12Mhz is fast enough 32 | 33 | // Set the orientation to draw in the direction we want 34 | lcd.setRotation(90); // the panel is actually 128 wide by 296 tall, but oriented 90 right 35 | lcd.allocBuffer(); // allocate a back buffer and keep it internal to the class 36 | lcd.fillScreen(OBD_WHITE); // 0 for EPDs is white (for OneBitDisplay) 37 | lcd.setFont(FONT_12x16); // use the internal stretched/smoothed font 38 | lcd.println("This was"); 39 | lcd.setTextColor(2); 40 | lcd.print("a full update"); 41 | lcd.display(); // do a full update 42 | } 43 | 44 | void loop() { 45 | // nothing going on here 46 | } 47 | -------------------------------------------------------------------------------- /examples/multi_oled_demo/multi_oled_demo.ino: -------------------------------------------------------------------------------- 1 | // 2 | // OneBitDisplay library multi-display demo 3 | // 4 | // Demonstrates how to initialize and use multiple displays 5 | // 6 | #include 7 | 8 | // Use -1 for the Wire library default pins 9 | // or specify the pin numbers to use with the Wire library or bit banging on any GPIO pins 10 | // These are reversed because I did straight-through wiring for my SSD1306 11 | // and it has the 4-pin header as GND,VCC,SCL,SDA, but the GROVE connector is 12 | // GND,VCC,SDA,SCL 13 | #define GROVE_SDA_PIN 32 14 | #define GROVE_SCL_PIN 26 15 | // These are the pin numbers for the M5Stack Atom default I2C 16 | #define SDA_PIN 21 17 | #define SCL_PIN 22 18 | // Set this to -1 to disable or the GPIO pin number connected to the reset 19 | // line of your display if it requires an external reset 20 | #define RESET_PIN -1 21 | // let ss_oled figure out the display address 22 | #define OLED_ADDR -1 23 | // don't rotate the display 24 | #define FLIP180 0 25 | // don't invert the display 26 | #define INVERT 0 27 | // Bit-Bang the I2C bus 28 | #define USE_HW_I2C 0 29 | 30 | // Change these if you're using different OLED displays 31 | #define MY_OLED1 OLED_128x64 32 | #define MY_OLED2 OLED_64x32 33 | 34 | // 2 copies of the SSOLED structure. Each structure is about 56 bytes 35 | // There is no limit to the number of simultaneous displays which can be controlled by ss_oled 36 | OBDISP obd[2]; 37 | 38 | void setup() { 39 | char *msgs[] = {(char *)"SSD1306 @ 0x3C", (char *)"SSD1306 @ 0x3D",(char *)"SH1106 @ 0x3C",(char *)"SH1106 @ 0x3D"}; 40 | int rc; 41 | // The I2C SDA/SCL pins set to -1 means to use the default Wire library 42 | // If pins were specified, they would be bit-banged in software 43 | // This isn't inferior to hw I2C and in fact allows you to go faster on certain CPUs 44 | // The reset pin is optional and I've only seen it needed on larger OLEDs (2.4") 45 | // that can be configured as either SPI or I2C 46 | // 47 | // obdI2CInit(OBDISP *, type, oled_addr, rotate180, invert, bWire, SDA_PIN, SCL_PIN, RESET_PIN, speed) 48 | 49 | rc = obdI2CInit(&obd[0], MY_OLED1, OLED_ADDR, FLIP180, INVERT, 1, SDA_PIN, SCL_PIN, RESET_PIN, 400000L); // use standard I2C bus at 400Khz 50 | if (rc != OLED_NOT_FOUND) 51 | { 52 | obdFill(&obd[0], OBD_WHITE, 1); 53 | obdWriteString(&obd[0], 0,0,0,msgs[rc], FONT_8x8, OBD_BLACK, 1); 54 | obdWriteString(&obd[0], 0,8,3,(char *)"Display", FONT_16x16, OBD_BLACK, 1); 55 | obdWriteString(&obd[0], 0,56,6,(char *)"0", FONT_16x16, OBD_BLACK, 1); 56 | } 57 | rc = obdI2CInit(&obd[1], MY_OLED2, OLED_ADDR, FLIP180, INVERT, 0, GROVE_SDA_PIN, GROVE_SCL_PIN, RESET_PIN, 400000L); // use standard I2C bus at 400Khz 58 | if (rc != OLED_NOT_FOUND) 59 | { 60 | obdFill(&obd[1], OBD_WHITE, 1); 61 | obdSetTextWrap(&obd[1], 1); 62 | obdWriteString(&obd[1], 0,0,0,msgs[rc], FONT_6x8, OBD_BLACK, 1); 63 | obdWriteString(&obd[1], 0,4,2,(char *)"Display", FONT_8x8, OBD_BLACK, 1); 64 | obdWriteString(&obd[1], 0,28,3,(char *)"1", FONT_8x8, OBD_BLACK, 1); 65 | } 66 | } /* setup() */ 67 | 68 | void loop() { 69 | // put your main code here, to run repeatedly: 70 | 71 | } /* loop() */ 72 | -------------------------------------------------------------------------------- /examples/obd_class_demo/obd_class_demo.ino: -------------------------------------------------------------------------------- 1 | // 2 | // Simple demo sketch to show how to use the new 3 | // C++ class which wraps the OneBitDisplay C API 4 | // This class was modeled after the Adafruit GFX API 5 | // to make it easier to port code, yet still retains 6 | // the unique features of OBD 7 | // 8 | // Written by Larry Bank 9 | // project started April 24, 2022 10 | // 11 | #include 12 | ONE_BIT_DISPLAY tft; // static class instantiation 13 | 14 | void setup() 15 | { 16 | int i; 17 | // The I2Cbegin() method needs a minimum of the type of OLED/LCD being used 18 | // Optional parameters are for the I2C address (auto discovered if not specified) 19 | // and the I2C bus speed (defaults to 400Kbs) 20 | // The Arduino default I2C pins are used here (works on many setups) 21 | // If you need to specify them, use the setI2CPins() method 22 | tft.I2Cbegin(OLED_64x128); 23 | // 24 | // Here we're asking the library to allocate the backing buffer 25 | // If successful, the library will change the render flag to "RAM only" so that 26 | // all drawing occurs only to the internal buffer, and display() must be called 27 | // to see the changes. Without a backing buffer, the API will try to draw all 28 | // output directly to the display instead. 29 | // 30 | if (!tft.allocBuffer()) { 31 | tft.print("Alloc failed"); 32 | } 33 | // tft.setRotation(3); // optionally rotate in 90 degree increments - only supports 0/180 without a RAM backing buffer 34 | tft.fillScreen(OBD_WHITE); 35 | tft.setScroll(true); // enable text printing to scroll the display buffer a line at a time 36 | tft.setFont(FONT_12x16); // Use the 6x8 (stretched+smoothed) font 37 | i = 0; 38 | while (1) { 39 | tft.print("Count = "); 40 | tft.println(i++, DEC); // this will keep the last line blank because it immediately scrolls up 41 | tft.display(); // copy the RAM buffer to the physical display 42 | delay(250); // slow it down a bit 43 | } 44 | } 45 | 46 | void loop() { 47 | // nothing going on here 48 | } 49 | -------------------------------------------------------------------------------- /examples/obd_cmd_demo/obd_cmd_demo.ino: -------------------------------------------------------------------------------- 1 | // 2 | // OneBitDisplay command example 3 | // shows how to create and play back a buffer of bytewise display commands 4 | // written by Larry Bank 1/23/2022 5 | // 6 | #include 7 | OBDISP obd, obdCMD; 8 | uint8_t ucBuffer[1024], ucBackBuffer[1024]; 9 | // 16x16 X image 10 | uint8_t ucSprite[32] = {0x80,0x01,0x40,0x02,0x20,0x04,0x10,0x08, 11 | 0x08,0x10,0x04,0x20,0x02,0x40,0x01,0x80, 12 | 0x01,0x80,0x02,0x40,0x04,0x20,0x08,0x10, 13 | 0x10,0x08,0x20,0x04,0x40,0x02,0x80,0x01}; 14 | void setup() { 15 | int rc; 16 | char szTemp[32]; 17 | // int obdI2CInit(OBDISP *pOBD, int iType, int iAddr, int bFlip, int bInvert, int bWire, int iSDAPin, int iSCLPin, int iResetPin, int32_t iSpeed); 18 | rc = obdI2CInit(&obd, OLED_128x64, -1, 0, 0, 1, -1, -1, -1, 800000); 19 | obdSetBackBuffer(&obd, ucBackBuffer); 20 | obdFill(&obd, OBD_WHITE, 1); 21 | memset(&obdCMD, 0, sizeof(obdCMD)); // ready for commands 22 | obdSetBackBuffer(&obdCMD, ucBuffer); // give it a memory space to save the commands 23 | 24 | obdWriteString(&obd, 0,0,0, (char *)"OBD Command test", FONT_8x8, OBD_BLACK, 1); 25 | obdWriteString(&obd, 0,0,1, (char *)"Executing...", FONT_8x8, OBD_BLACK, 1); 26 | obdFill(&obdCMD, OBD_WHITE, 1); 27 | obdWriteString(&obdCMD, 0,0,0,(char *)"The OBD lib functions", FONT_6x8, OBD_BLACK, 1); 28 | obdWriteString(&obdCMD, 0,0,1,(char *)"become byte codes", FONT_6x8, OBD_BLACK, 1); 29 | obdWriteString(&obdCMD, 0,0,2,(char *)"written into memory", FONT_6x8, OBD_BLACK, 1); 30 | obdWriteString(&obdCMD, 0,0,3,(char *)"and then played back", FONT_6x8, OBD_BLACK, 1); 31 | obdEllipse(&obdCMD, 32, 48, 31, 15, OBD_BLACK, 1); 32 | obdEllipse(&obdCMD, 32, 48, 15, 12, OBD_WHITE, 1); 33 | obdDrawSprite(&obdCMD, ucSprite, 16, 16, 2, 96,40, 1); 34 | // obdEllipse(&obdCMD, 96, 48, 31, 15, 1, 1); 35 | // obdEllipse(&obdCMD, 96, 48, 15, 12, 0, 1); 36 | sprintf(szTemp, "%d bytes generated", obdGetCommandLen(&obdCMD)); 37 | obdWriteString(&obd, 0,0,2, szTemp, FONT_6x8, OBD_BLACK, 1); 38 | delay(4000); 39 | obdExecCommands(ucBuffer, obdGetCommandLen(&obdCMD), &obd, 0); 40 | obdDumpBuffer(&obd, NULL); 41 | } /* setup() */ 42 | 43 | void loop() { 44 | // put your main code here, to run repeatedly: 45 | 46 | } 47 | -------------------------------------------------------------------------------- /examples/oled_gfx_demo/oled_gfx_demo.ino: -------------------------------------------------------------------------------- 1 | // 2 | // OneBitDisplay library GFX demo 3 | // 4 | #include 5 | 6 | // Use -1 for the Wire library default pins 7 | // or specify the pin numbers to use with the Wire library or bit banging on any GPIO pins 8 | // These are reversed because I did straight-through wiring for my SSD1306 9 | // and it has the 4-pin header as GND,VCC,SCL,SDA, but the GROVE connector is 10 | // GND,VCC,SDA,SCL 11 | // Even though I've wired the SDA/SCL pins backwards, the ESP32 can still use 12 | // the hardware I2C device because of the flexible pin definitions 13 | #define GROVE_SDA_PIN 32 14 | #define GROVE_SCL_PIN 26 15 | // Set this to -1 to disable or the GPIO pin number connected to the reset 16 | // line of your display if it requires an external reset 17 | #define RESET_PIN -1 18 | // let OneBitDisplay figure out the display address 19 | #define OLED_ADDR -1 20 | // don't rotate the display 21 | #define FLIP180 0 22 | // don't invert the display 23 | #define INVERT 0 24 | // Bit-Bang the I2C bus 25 | #define USE_HW_I2C 1 26 | 27 | // Change this if you're using different OLED displays 28 | #define MY_OLED OLED_128x64 29 | uint8_t ucBackBuffer[1024]; 30 | 31 | // The OBDISP structure 32 | // There is no limit to the number of simultaneous displays which can be controlled by OneBitDisplay 33 | OBDISP obd; 34 | 35 | void setup() { 36 | char *msgs[] = {(char *)"SSD1306 @ 0x3C", (char *)"SSD1306 @ 0x3D",(char *)"SH1106 @ 0x3C",(char *)"SH1106 @ 0x3D"}; 37 | int rc; 38 | // The I2C SDA/SCL pins set to -1 means to use the default Wire library 39 | // If pins were specified, they would be bit-banged in software 40 | // This isn't inferior to hw I2C and in fact allows you to go faster on certain CPUs 41 | // The reset pin is optional and I've only seen it needed on larger OLEDs (2.4") 42 | // that can be configured as either SPI or I2C 43 | // 44 | // obdI2CInit(OBDISP *, type, oled_addr, rotate180, invert, bWire, SDA_PIN, SCL_PIN, RESET_PIN, speed) 45 | 46 | rc = obdI2CInit(&obd, MY_OLED, OLED_ADDR, FLIP180, INVERT, USE_HW_I2C, GROVE_SDA_PIN, GROVE_SCL_PIN, RESET_PIN, 800000L); // use standard I2C bus at 400Khz 47 | if (rc != OLED_NOT_FOUND) 48 | { 49 | obdFill(&obd, OBD_WHITE, 1); 50 | obdWriteString(&obd, 0,0,0,msgs[rc], FONT_8x8, OBD_BLACK, 1); 51 | delay(2000); 52 | } 53 | else 54 | { 55 | while (1) {}; 56 | } 57 | obdSetBackBuffer(&obd, ucBackBuffer); 58 | } /* setup() */ 59 | 60 | #define DRAW_ELLIPSES 61 | #define DRAW_RECTS 62 | 63 | void loop() { 64 | int i, x, y, x2, y2, r1, r2; 65 | uint8_t ucColor; 66 | 67 | #ifdef DRAW_ELLIPSES 68 | obdFill(&obd, OBD_WHITE, 1); 69 | obdWriteString(&obd, 0, 0, 0, (char *)"Ellipses", FONT_8x8, OBD_BLACK, 1); 70 | delay(2000); 71 | obdFill(&obd, OBD_WHITE, 1); 72 | for (i=0; i<100; i++) 73 | { 74 | x = random(128); 75 | y = random(64); 76 | r1 = random(64); 77 | r2 = random(32); 78 | obdEllipse(&obd, x, y, r1, r2, OBD_BLACK, 0); 79 | obdDumpBuffer(&obd, NULL); 80 | } 81 | obdFill(&obd, OBD_WHITE, 1); 82 | obdWriteString(&obd, 0, 0, 0, (char *)"Filled Ellipses", FONT_8x8, OBD_BLACK, 1); 83 | delay(2000); 84 | obdFill(&obd, OBD_WHITE, 1); 85 | for (i=0; i<100; i++) 86 | { 87 | x = random(128); 88 | y = random(64); 89 | r1 = random(64); 90 | r2 = random(32); 91 | ucColor = random(2); 92 | obdEllipse(&obd, x, y, r1, r2, ucColor, 1); 93 | obdDumpBuffer(&obd, NULL); 94 | } 95 | #endif // DRAW_ELLIPSES 96 | 97 | #ifdef DRAW_RECTS 98 | obdFill(&obd, OBD_WHITE, 1); 99 | obdWriteString(&obd, 0, 0, 0, (char *)"Rectangles", FONT_8x8, OBD_BLACK, 1); 100 | delay(2000); 101 | obdFill(&obd, OBD_WHITE, 1); 102 | for (i=0; i<100; i++) 103 | { 104 | x = random(128); 105 | y = random(64); 106 | x2 = random(128); 107 | y2 = random(64); 108 | obdRectangle(&obd, x, y, x2, y2, OBD_BLACK, 0); 109 | obdDumpBuffer(&obd, NULL); 110 | } 111 | obdFill(&obd, OBD_WHITE, 1); 112 | obdWriteString(&obd, 0, 0, 0, (char *)"Filled Rects", FONT_8x8, OBD_BLACK, 1); 113 | delay(2000); 114 | obdFill(&obd, OBD_WHITE, 1); 115 | for (i=0; i<100; i++) 116 | { 117 | x = random(128); 118 | y = random(64); 119 | x2 = random(128); 120 | y2 = random(64); 121 | ucColor = random(2); 122 | obdRectangle(&obd, x, y, x2, y2, ucColor, 1); 123 | obdDumpBuffer(&obd, NULL); 124 | } 125 | #endif // DRAW_RECTS 126 | 127 | delay(4000); 128 | } /* loop() */ 129 | -------------------------------------------------------------------------------- /examples/onebit_lcd_test/onebit_lcd_test.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | OBDISP obd; 4 | #define FLIP180 0 5 | #define INVERT 0 6 | #define BITBANG 1 7 | #define DC_PIN 22 8 | #define CS_PIN 3 9 | #define RESET_PIN 1 10 | #define MOSI_PIN 19 11 | #define CLK_PIN 23 12 | #define LED_PIN 18 13 | void setup() { 14 | // put your setup code here, to run once: 15 | //void obdSPIInit(OBDISP *pOBD, int iType, int iDC, int iCS, int iReset, int iMOSI, int iCLK, int iLED, int bFlip, int bInvert, int bBitBang, int32_t iSpeed) 16 | obdSPIInit(&obd, LCD_UC1701, DC_PIN, CS_PIN, RESET_PIN, MOSI_PIN, CLK_PIN, LED_PIN, FLIP180, INVERT, BITBANG, 0); 17 | obdFill(&obd, OBD_WHITE, 1); 18 | } 19 | 20 | void loop() { 21 | // put your main code here, to run repeatedly: 22 | obdWriteString(&obd, 0, 0, 0, (char *)"Hello World!", FONT_8x8, OBD_BLACK, 1); 23 | while (1) 24 | { 25 | 26 | }; 27 | 28 | } 29 | -------------------------------------------------------------------------------- /examples/pico_oled_13_demo/pico_oled_13_demo.ino: -------------------------------------------------------------------------------- 1 | // 2 | // OneBitDisplay WaveShare Pico OLED 1.3 demo sketch 3 | // Written by Larry Bank 7/12/2022 4 | // 5 | #include 6 | 7 | ONE_BIT_DISPLAY lcd; 8 | 9 | #define PICO_FREQ 10000000 10 | #define PICO_CS 9 11 | #define PICO_LED -1 12 | #define PICO_RES 12 13 | #define PICO_DC 8 14 | #define PICO_MOSI 11 15 | #define PICO_SCK 10 16 | 17 | void setup() { 18 | // Initialize the library by telling it how the display is connected 19 | lcd.setSPIPins(PICO_CS, PICO_MOSI, PICO_SCK, PICO_DC, PICO_RES, PICO_LED); 20 | lcd.SPIbegin(OLED_64x128, PICO_FREQ); 21 | 22 | // Set the orientation to draw in the direction we want 23 | lcd.allocBuffer(); // allocate a back buffer and keep it internal to the class 24 | lcd.setRotation(90); // the panel is actually 64 wide by 128 tall, but oriented 90 right 25 | // To draw characters rotated 90/270 we need to allocate a back buffer 26 | lcd.fillScreen(OBD_WHITE); // 0 for EPDs is white (for OneBitDisplay) 27 | lcd.setFont(FONT_12x16); // use the internal stretched/smoothed font 28 | lcd.println("WaveShare"); 29 | lcd.println("Pico-OLED"); 30 | lcd.println("Demo"); 31 | lcd.display(); // update 32 | } /* setup() */ 33 | 34 | void loop() { 35 | int i; 36 | for (i=0; i<2047; i++) { 37 | int x, y; 38 | x = rand() & 127; 39 | y = rand() & 63; 40 | lcd.drawPixel(x, y, 1); 41 | if ((i & 3) == 3) 42 | lcd.display(); 43 | } 44 | lcd.setFont(FONT_6x8); 45 | lcd.setScroll(true); 46 | lcd.fillScreen(OBD_WHITE); 47 | i = 0; 48 | while (1) { 49 | lcd.println(i++, DEC); 50 | lcd.display(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /examples/prop_font_demo/FreeSerif12pt7b.h: -------------------------------------------------------------------------------- 1 | const uint8_t FreeSerif12pt7bBitmaps[] PROGMEM = { 2 | 0xFF, 0xFE, 0xA8, 0x3F, 0xCF, 0x3C, 0xF3, 0x8A, 0x20, 0x0C, 0x40, 0xC4, 3 | 0x08, 0x40, 0x8C, 0x08, 0xC7, 0xFF, 0x18, 0x81, 0x88, 0x10, 0x81, 0x08, 4 | 0xFF, 0xE1, 0x18, 0x31, 0x03, 0x10, 0x31, 0x02, 0x10, 0x04, 0x07, 0xC6, 5 | 0x5B, 0x12, 0xC4, 0xB1, 0x0F, 0x41, 0xF0, 0x1E, 0x01, 0xE0, 0x58, 0x13, 6 | 0x84, 0xE1, 0x3C, 0x4F, 0x96, 0x3F, 0x01, 0x00, 0x00, 0x04, 0x03, 0x83, 7 | 0x03, 0x9F, 0x81, 0xC2, 0x20, 0x60, 0x90, 0x38, 0x24, 0x0C, 0x12, 0x03, 8 | 0x0D, 0x00, 0xC6, 0x47, 0x9E, 0x23, 0x10, 0x09, 0x84, 0x04, 0xE1, 0x03, 9 | 0x30, 0x40, 0x8C, 0x20, 0x43, 0x08, 0x10, 0xC4, 0x08, 0x1E, 0x00, 0x03, 10 | 0xC0, 0x02, 0x30, 0x03, 0x08, 0x01, 0x84, 0x00, 0xC4, 0x00, 0x7C, 0xF8, 11 | 0x1C, 0x38, 0x1E, 0x08, 0x33, 0x0C, 0x31, 0xC4, 0x10, 0x74, 0x18, 0x3A, 12 | 0x0C, 0x0E, 0x07, 0x03, 0x83, 0xC3, 0xE2, 0x7E, 0x3E, 0xFF, 0xA0, 0x04, 13 | 0x21, 0x08, 0x61, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC1, 0x04, 0x18, 0x20, 14 | 0x40, 0x81, 0x81, 0x02, 0x04, 0x18, 0x20, 0x83, 0x0C, 0x30, 0xC3, 0x0C, 15 | 0x30, 0x86, 0x10, 0x84, 0x20, 0x30, 0xB3, 0xD7, 0x54, 0x38, 0x7C, 0xD3, 16 | 0x30, 0x30, 0x10, 0x04, 0x00, 0x80, 0x10, 0x02, 0x00, 0x41, 0xFF, 0xC1, 17 | 0x00, 0x20, 0x04, 0x00, 0x80, 0x10, 0x00, 0xDF, 0x95, 0x00, 0xFC, 0xFC, 18 | 0x06, 0x0C, 0x10, 0x60, 0xC1, 0x06, 0x0C, 0x10, 0x60, 0xC1, 0x06, 0x0C, 19 | 0x10, 0x60, 0xC0, 0x1E, 0x0C, 0xC6, 0x19, 0x86, 0xC0, 0xB0, 0x3C, 0x0F, 20 | 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xD8, 0x66, 0x18, 0xCC, 0x1E, 21 | 0x00, 0x11, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 22 | 0x0C, 0xFC, 0x1E, 0x18, 0xC4, 0x1A, 0x06, 0x01, 0x80, 0x60, 0x10, 0x0C, 23 | 0x02, 0x01, 0x00, 0xC0, 0x60, 0x30, 0x18, 0x1F, 0xF8, 0x1E, 0x18, 0xE8, 24 | 0x18, 0x06, 0x01, 0x00, 0x80, 0xF0, 0x7E, 0x03, 0xC0, 0x70, 0x0C, 0x03, 25 | 0x00, 0xC0, 0x6E, 0x11, 0xF8, 0x01, 0x00, 0xC0, 0x70, 0x2C, 0x0B, 0x04, 26 | 0xC2, 0x30, 0x8C, 0x43, 0x20, 0xC8, 0x33, 0xFF, 0x03, 0x00, 0xC0, 0x30, 27 | 0x0C, 0x00, 0x03, 0xF1, 0x00, 0x40, 0x18, 0x0F, 0x80, 0xF8, 0x0E, 0x01, 28 | 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x20, 0x1B, 0x8C, 0x7C, 0x00, 0x01, 29 | 0xC3, 0xC1, 0xC0, 0xC0, 0x70, 0x18, 0x0E, 0xF3, 0xCE, 0xC1, 0xF0, 0x3C, 30 | 0x0F, 0x03, 0xC0, 0xD8, 0x36, 0x08, 0xC6, 0x1E, 0x00, 0x3F, 0xD0, 0x38, 31 | 0x08, 0x06, 0x01, 0x80, 0x40, 0x10, 0x0C, 0x02, 0x00, 0x80, 0x20, 0x10, 32 | 0x04, 0x01, 0x00, 0x80, 0x20, 0x1F, 0x18, 0x6C, 0x0F, 0x03, 0xC0, 0xF8, 33 | 0x67, 0x30, 0xF0, 0x1E, 0x09, 0xE6, 0x3B, 0x07, 0xC0, 0xF0, 0x3C, 0x0D, 34 | 0x86, 0x1F, 0x00, 0x1E, 0x08, 0xC6, 0x1B, 0x02, 0xC0, 0xF0, 0x3C, 0x0F, 35 | 0x03, 0xE0, 0xDC, 0x73, 0xEC, 0x06, 0x01, 0x80, 0xC0, 0x70, 0x38, 0x38, 36 | 0x18, 0x00, 0xFC, 0x00, 0x3F, 0xCC, 0xC0, 0x00, 0x00, 0x06, 0x77, 0x12, 37 | 0x40, 0x00, 0x00, 0x07, 0x01, 0xE0, 0x78, 0x1E, 0x07, 0x00, 0xC0, 0x0F, 38 | 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x07, 0x00, 0x10, 0xFF, 0xF0, 0x00, 39 | 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0x80, 0x0E, 0x00, 0x3C, 0x00, 0xF0, 40 | 0x03, 0xC0, 0x0F, 0x00, 0x30, 0x0E, 0x07, 0x81, 0xE0, 0x78, 0x0E, 0x00, 41 | 0x00, 0x00, 0x7C, 0x86, 0x83, 0xC3, 0x03, 0x03, 0x06, 0x0C, 0x08, 0x08, 42 | 0x10, 0x10, 0x00, 0x00, 0x30, 0x30, 0x30, 0x03, 0xF0, 0x06, 0x06, 0x06, 43 | 0x00, 0x86, 0x00, 0x26, 0x0E, 0xD3, 0x0C, 0xC7, 0x0C, 0x63, 0x84, 0x31, 44 | 0xC6, 0x18, 0xE3, 0x08, 0x71, 0x8C, 0x4C, 0xC6, 0x46, 0x3D, 0xC1, 0x80, 45 | 0x00, 0x30, 0x10, 0x07, 0xF0, 0x00, 0x80, 0x00, 0x60, 0x00, 0x70, 0x00, 46 | 0x38, 0x00, 0x2E, 0x00, 0x13, 0x00, 0x19, 0xC0, 0x08, 0x60, 0x04, 0x38, 47 | 0x04, 0x0C, 0x03, 0xFF, 0x03, 0x03, 0x81, 0x00, 0xE1, 0x80, 0x70, 0xC0, 48 | 0x3D, 0xF0, 0x3F, 0xFF, 0x83, 0x0C, 0x30, 0x63, 0x06, 0x30, 0x63, 0x06, 49 | 0x30, 0xC3, 0xF0, 0x30, 0xE3, 0x06, 0x30, 0x33, 0x03, 0x30, 0x33, 0x07, 50 | 0x30, 0xEF, 0xFC, 0x07, 0xE2, 0x38, 0x3C, 0xC0, 0x3B, 0x00, 0x36, 0x00, 51 | 0x38, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x03, 52 | 0x00, 0x06, 0x00, 0x06, 0x00, 0x47, 0x03, 0x03, 0xF8, 0xFF, 0xC0, 0x30, 53 | 0x78, 0x30, 0x1C, 0x30, 0x0E, 0x30, 0x06, 0x30, 0x03, 0x30, 0x03, 0x30, 54 | 0x03, 0x30, 0x03, 0x30, 0x03, 0x30, 0x03, 0x30, 0x06, 0x30, 0x06, 0x30, 55 | 0x0C, 0x30, 0x78, 0xFF, 0xC0, 0xFF, 0xFC, 0xC0, 0x33, 0x00, 0x4C, 0x00, 56 | 0x30, 0x00, 0xC0, 0x43, 0x03, 0x0F, 0xFC, 0x30, 0x30, 0xC0, 0x43, 0x00, 57 | 0x0C, 0x00, 0x30, 0x08, 0xC0, 0x23, 0x03, 0xBF, 0xFE, 0xFF, 0xFC, 0xC0, 58 | 0x33, 0x00, 0x4C, 0x00, 0x30, 0x00, 0xC0, 0x43, 0x03, 0x0F, 0xFC, 0x30, 59 | 0x30, 0xC0, 0x43, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x3F, 60 | 0x00, 0x07, 0xE4, 0x1C, 0x3C, 0x30, 0x0C, 0x60, 0x0C, 0x60, 0x04, 0xC0, 61 | 0x00, 0xC0, 0x00, 0xC0, 0x3F, 0xC0, 0x0C, 0xC0, 0x0C, 0xC0, 0x0C, 0x60, 62 | 0x0C, 0x60, 0x0C, 0x30, 0x0C, 0x1C, 0x1C, 0x07, 0xE0, 0xFC, 0x3F, 0x30, 63 | 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x3F, 64 | 0xFC, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 65 | 0x0C, 0x30, 0x0C, 0xFC, 0x3F, 0xFC, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 66 | 0xC3, 0x0C, 0x30, 0xC3, 0x3F, 0x3F, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 67 | 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xC8, 0xF0, 0xFC, 0xFE, 0x30, 68 | 0x38, 0x30, 0x20, 0x30, 0x40, 0x30, 0x80, 0x33, 0x00, 0x36, 0x00, 0x3E, 69 | 0x00, 0x37, 0x00, 0x33, 0x80, 0x31, 0xC0, 0x30, 0xE0, 0x30, 0x70, 0x30, 70 | 0x38, 0x30, 0x3C, 0xFC, 0x7F, 0xFC, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 71 | 0x03, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x30, 0x00, 0x60, 0x00, 72 | 0xC0, 0x01, 0x80, 0x03, 0x00, 0x26, 0x00, 0x8C, 0x07, 0x7F, 0xFE, 0xF8, 73 | 0x01, 0xE7, 0x00, 0x70, 0xE0, 0x0E, 0x1E, 0x03, 0xC2, 0xC0, 0x58, 0x5C, 74 | 0x1B, 0x09, 0x82, 0x61, 0x38, 0x4C, 0x27, 0x11, 0x84, 0x72, 0x30, 0x8E, 75 | 0xC6, 0x10, 0xD0, 0xC2, 0x1E, 0x18, 0x41, 0x83, 0x1C, 0x30, 0x67, 0xC4, 76 | 0x3F, 0xF0, 0x1F, 0x78, 0x0E, 0x3C, 0x04, 0x3E, 0x04, 0x2E, 0x04, 0x27, 77 | 0x04, 0x23, 0x84, 0x23, 0xC4, 0x21, 0xE4, 0x20, 0xE4, 0x20, 0x74, 0x20, 78 | 0x3C, 0x20, 0x1C, 0x20, 0x0C, 0x70, 0x0C, 0xF8, 0x04, 0x07, 0xC0, 0x30, 79 | 0x60, 0xC0, 0x63, 0x00, 0x66, 0x00, 0xD8, 0x00, 0xF0, 0x01, 0xE0, 0x03, 80 | 0xC0, 0x07, 0x80, 0x0F, 0x00, 0x1B, 0x00, 0x66, 0x00, 0xC6, 0x03, 0x06, 81 | 0x0C, 0x03, 0xE0, 0xFF, 0x83, 0x0E, 0x30, 0x73, 0x03, 0x30, 0x33, 0x03, 82 | 0x30, 0x63, 0x0E, 0x3F, 0x83, 0x00, 0x30, 0x03, 0x00, 0x30, 0x03, 0x00, 83 | 0x30, 0x0F, 0xC0, 0x0F, 0xE0, 0x18, 0x30, 0x30, 0x18, 0x60, 0x0C, 0x60, 84 | 0x0C, 0xC0, 0x06, 0xC0, 0x06, 0xC0, 0x06, 0xC0, 0x06, 0xC0, 0x06, 0xC0, 85 | 0x06, 0x60, 0x0C, 0x60, 0x0C, 0x30, 0x18, 0x18, 0x30, 0x07, 0xC0, 0x03, 86 | 0xC0, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x1F, 0xFF, 0x80, 0x61, 0xC0, 0xC1, 87 | 0xC1, 0x81, 0x83, 0x03, 0x06, 0x06, 0x0C, 0x1C, 0x18, 0x70, 0x3F, 0x80, 88 | 0x67, 0x00, 0xC7, 0x01, 0x8F, 0x03, 0x0F, 0x06, 0x0E, 0x0C, 0x0E, 0x7E, 89 | 0x0F, 0x1F, 0x46, 0x19, 0x81, 0x30, 0x27, 0x02, 0xF0, 0x0F, 0x00, 0xF8, 90 | 0x07, 0xC0, 0x38, 0x03, 0xC0, 0x34, 0x06, 0x80, 0xDC, 0x32, 0x7C, 0xFF, 91 | 0xFF, 0x86, 0x0E, 0x0C, 0x1C, 0x18, 0x10, 0x30, 0x00, 0x60, 0x00, 0xC0, 92 | 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x30, 0x00, 93 | 0x60, 0x00, 0xC0, 0x07, 0xE0, 0xFC, 0x1F, 0x30, 0x0E, 0x30, 0x04, 0x30, 94 | 0x04, 0x30, 0x04, 0x30, 0x04, 0x30, 0x04, 0x30, 0x04, 0x30, 0x04, 0x30, 95 | 0x04, 0x30, 0x04, 0x30, 0x04, 0x30, 0x04, 0x18, 0x08, 0x1C, 0x18, 0x07, 96 | 0xE0, 0xFE, 0x0F, 0x9C, 0x03, 0x0E, 0x01, 0x83, 0x00, 0x81, 0xC0, 0x40, 97 | 0x60, 0x40, 0x38, 0x20, 0x0C, 0x30, 0x07, 0x10, 0x01, 0x98, 0x00, 0xE8, 98 | 0x00, 0x34, 0x00, 0x1E, 0x00, 0x06, 0x00, 0x03, 0x00, 0x01, 0x00, 0xFC, 99 | 0xFC, 0x3D, 0xE1, 0xC0, 0x63, 0x83, 0x01, 0x86, 0x0E, 0x04, 0x1C, 0x18, 100 | 0x10, 0x70, 0x70, 0x80, 0xC3, 0xC2, 0x03, 0x8B, 0x08, 0x06, 0x6E, 0x40, 101 | 0x1D, 0x19, 0x00, 0x74, 0x78, 0x00, 0xE1, 0xE0, 0x03, 0x83, 0x80, 0x0E, 102 | 0x0C, 0x00, 0x10, 0x10, 0x00, 0x40, 0x40, 0x7F, 0x1F, 0x9E, 0x03, 0x07, 103 | 0x03, 0x01, 0xC3, 0x00, 0x71, 0x00, 0x19, 0x00, 0x0F, 0x00, 0x03, 0x80, 104 | 0x01, 0xE0, 0x01, 0xB0, 0x01, 0x9C, 0x00, 0x87, 0x00, 0x81, 0xC0, 0x80, 105 | 0xE0, 0xC0, 0x79, 0xF8, 0x7F, 0xFE, 0x1F, 0x78, 0x0C, 0x38, 0x08, 0x1C, 106 | 0x18, 0x0E, 0x10, 0x06, 0x20, 0x07, 0x60, 0x03, 0xC0, 0x01, 0x80, 0x01, 107 | 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x07, 108 | 0xE0, 0x7F, 0xFB, 0x00, 0xC8, 0x07, 0x20, 0x38, 0x01, 0xC0, 0x07, 0x00, 109 | 0x38, 0x01, 0xC0, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x0E, 0x00, 0x38, 0x05, 110 | 0xC0, 0x3E, 0x01, 0xBF, 0xFE, 0xFE, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x31, 111 | 0x8C, 0x63, 0x18, 0xC6, 0x31, 0xF0, 0xC1, 0x81, 0x03, 0x06, 0x04, 0x0C, 112 | 0x18, 0x10, 0x30, 0x60, 0x40, 0xC1, 0x81, 0x03, 0x06, 0xF8, 0xC6, 0x31, 113 | 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xC7, 0xF0, 0x0C, 0x07, 114 | 0x01, 0x60, 0xD8, 0x23, 0x18, 0xC4, 0x1B, 0x06, 0x80, 0xC0, 0xFF, 0xF0, 115 | 0xC7, 0x0C, 0x30, 0x3E, 0x31, 0x8C, 0x30, 0x0C, 0x03, 0x07, 0xC6, 0x33, 116 | 0x0C, 0xC3, 0x31, 0xC7, 0xB8, 0x20, 0x38, 0x06, 0x01, 0x80, 0x60, 0x18, 117 | 0x06, 0xF1, 0xC6, 0x61, 0xD8, 0x36, 0x0D, 0x83, 0x60, 0xD8, 0x26, 0x19, 118 | 0x84, 0x3E, 0x00, 0x1E, 0x23, 0x63, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xE1, 119 | 0x72, 0x3C, 0x00, 0x80, 0xE0, 0x18, 0x06, 0x01, 0x80, 0x61, 0xD8, 0x8E, 120 | 0x61, 0xB0, 0x6C, 0x1B, 0x06, 0xC1, 0xB0, 0x6E, 0x19, 0xCE, 0x3D, 0xC0, 121 | 0x1E, 0x08, 0xE4, 0x1B, 0xFE, 0xC0, 0x30, 0x0C, 0x03, 0x81, 0x60, 0x9C, 122 | 0x41, 0xE0, 0x0F, 0x08, 0xC4, 0x06, 0x03, 0x01, 0x81, 0xF0, 0x60, 0x30, 123 | 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x60, 0xFC, 0x00, 0x1F, 0x03, 124 | 0x1F, 0x60, 0xC6, 0x0C, 0x60, 0xC3, 0x18, 0x1F, 0x02, 0x00, 0x40, 0x07, 125 | 0xFC, 0x40, 0x24, 0x02, 0xC0, 0x2C, 0x04, 0xE0, 0x83, 0xF0, 0x30, 0x1E, 126 | 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0D, 0xE1, 0xCE, 0x30, 0xC6, 0x18, 127 | 0xC3, 0x18, 0x63, 0x0C, 0x61, 0x8C, 0x31, 0x86, 0x79, 0xE0, 0x31, 0x80, 128 | 0x00, 0x09, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xDF, 0x0C, 0x30, 0x00, 0x00, 129 | 0x31, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xF2, 0xF0, 130 | 0x20, 0x1C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0xFB, 0x08, 0x62, 131 | 0x0C, 0x81, 0xE0, 0x3E, 0x06, 0xE0, 0xCE, 0x18, 0xC3, 0x0E, 0xF3, 0xE0, 132 | 0x13, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0xF8, 0xF7, 133 | 0x8F, 0x0E, 0x3C, 0xE3, 0x0C, 0x18, 0xC3, 0x06, 0x30, 0xC1, 0x8C, 0x30, 134 | 0x63, 0x0C, 0x18, 0xC3, 0x06, 0x30, 0xC1, 0x8C, 0x30, 0x67, 0x9E, 0x3C, 135 | 0xF7, 0x87, 0x18, 0xC3, 0x18, 0x63, 0x0C, 0x61, 0x8C, 0x31, 0x86, 0x30, 136 | 0xC6, 0x19, 0xE7, 0x80, 0x1E, 0x18, 0xE4, 0x1B, 0x03, 0xC0, 0xF0, 0x3C, 137 | 0x0F, 0x03, 0x60, 0x9C, 0x41, 0xE0, 0x77, 0x87, 0x18, 0xC3, 0x98, 0x33, 138 | 0x06, 0x60, 0xCC, 0x19, 0x83, 0x30, 0xC7, 0x10, 0xDC, 0x18, 0x03, 0x00, 139 | 0x60, 0x0C, 0x07, 0xE0, 0x1E, 0x8C, 0xE6, 0x1B, 0x06, 0xC1, 0xB0, 0x6C, 140 | 0x1B, 0x06, 0xE1, 0x98, 0xE3, 0xD8, 0x06, 0x01, 0x80, 0x60, 0x18, 0x1F, 141 | 0x37, 0x7B, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x7C, 0x7B, 142 | 0x0E, 0x1C, 0x1E, 0x0F, 0x07, 0xC3, 0x87, 0x8A, 0xE0, 0x21, 0x8F, 0x98, 143 | 0x61, 0x86, 0x18, 0x61, 0x86, 0x19, 0x38, 0xE3, 0x98, 0x66, 0x19, 0x86, 144 | 0x61, 0x98, 0x66, 0x19, 0x86, 0x61, 0x9C, 0xE3, 0xDC, 0xF8, 0xEE, 0x08, 145 | 0xC1, 0x18, 0x41, 0x88, 0x32, 0x03, 0x40, 0x68, 0x06, 0x00, 0xC0, 0x10, 146 | 0x00, 0xF3, 0xE7, 0x61, 0x83, 0x70, 0xC2, 0x30, 0xC2, 0x30, 0xC4, 0x19, 147 | 0x64, 0x19, 0x68, 0x0E, 0x38, 0x0E, 0x38, 0x0C, 0x30, 0x04, 0x10, 0xFB, 148 | 0xC6, 0x30, 0x64, 0x0F, 0x00, 0xC0, 0x0C, 0x03, 0xC0, 0x98, 0x21, 0x8C, 149 | 0x3B, 0xCF, 0x80, 0xF8, 0xEE, 0x08, 0xC1, 0x18, 0x41, 0x88, 0x31, 0x03, 150 | 0x40, 0x68, 0x06, 0x00, 0xC0, 0x08, 0x02, 0x00, 0x40, 0x10, 0x1E, 0x03, 151 | 0x80, 0x7F, 0x90, 0xE0, 0x30, 0x18, 0x0E, 0x03, 0x01, 0xC0, 0xE0, 0x30, 152 | 0x5C, 0x3F, 0xF8, 0x19, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0xB0, 0x63, 0x18, 153 | 0xC6, 0x31, 0x8C, 0x61, 0x80, 0xFF, 0xFF, 0x80, 0xC3, 0x18, 0xC6, 0x31, 154 | 0x8C, 0x63, 0x06, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xCC, 0x00, 0x38, 0x06, 155 | 0x62, 0x41, 0xC0}; 156 | 157 | const GFXglyph FreeSerif12pt7bGlyphs[] PROGMEM = { 158 | {0, 0, 0, 6, 0, 1}, // 0x20 ' ' 159 | {0, 2, 16, 8, 3, -15}, // 0x21 '!' 160 | {4, 6, 6, 10, 1, -15}, // 0x22 '"' 161 | {9, 12, 16, 12, 0, -15}, // 0x23 '#' 162 | {33, 10, 18, 12, 1, -16}, // 0x24 '$' 163 | {56, 18, 17, 20, 1, -16}, // 0x25 '%' 164 | {95, 17, 16, 19, 1, -15}, // 0x26 '&' 165 | {129, 2, 6, 5, 1, -15}, // 0x27 ''' 166 | {131, 6, 20, 8, 1, -15}, // 0x28 '(' 167 | {146, 6, 20, 8, 1, -15}, // 0x29 ')' 168 | {161, 8, 10, 12, 3, -14}, // 0x2A '*' 169 | {171, 11, 11, 14, 1, -10}, // 0x2B '+' 170 | {187, 3, 6, 6, 2, -2}, // 0x2C ',' 171 | {190, 6, 1, 8, 1, -5}, // 0x2D '-' 172 | {191, 2, 3, 6, 2, -2}, // 0x2E '.' 173 | {192, 7, 17, 7, 0, -16}, // 0x2F '/' 174 | {207, 10, 17, 12, 1, -16}, // 0x30 '0' 175 | {229, 6, 17, 12, 3, -16}, // 0x31 '1' 176 | {242, 10, 15, 12, 1, -14}, // 0x32 '2' 177 | {261, 10, 16, 12, 1, -15}, // 0x33 '3' 178 | {281, 10, 16, 12, 1, -15}, // 0x34 '4' 179 | {301, 10, 17, 12, 1, -16}, // 0x35 '5' 180 | {323, 10, 17, 12, 1, -16}, // 0x36 '6' 181 | {345, 10, 16, 12, 0, -15}, // 0x37 '7' 182 | {365, 10, 17, 12, 1, -16}, // 0x38 '8' 183 | {387, 10, 18, 12, 1, -16}, // 0x39 '9' 184 | {410, 2, 12, 6, 2, -11}, // 0x3A ':' 185 | {413, 4, 15, 6, 2, -11}, // 0x3B ';' 186 | {421, 12, 13, 14, 1, -12}, // 0x3C '<' 187 | {441, 12, 6, 14, 1, -8}, // 0x3D '=' 188 | {450, 12, 13, 14, 1, -11}, // 0x3E '>' 189 | {470, 8, 17, 11, 2, -16}, // 0x3F '?' 190 | {487, 17, 16, 21, 2, -15}, // 0x40 '@' 191 | {521, 17, 16, 17, 0, -15}, // 0x41 'A' 192 | {555, 12, 16, 15, 1, -15}, // 0x42 'B' 193 | {579, 15, 16, 16, 1, -15}, // 0x43 'C' 194 | {609, 16, 16, 17, 0, -15}, // 0x44 'D' 195 | {641, 14, 16, 15, 0, -15}, // 0x45 'E' 196 | {669, 14, 16, 14, 0, -15}, // 0x46 'F' 197 | {697, 16, 16, 17, 1, -15}, // 0x47 'G' 198 | {729, 16, 16, 17, 0, -15}, // 0x48 'H' 199 | {761, 6, 16, 8, 1, -15}, // 0x49 'I' 200 | {773, 8, 16, 9, 0, -15}, // 0x4A 'J' 201 | {789, 16, 16, 17, 1, -15}, // 0x4B 'K' 202 | {821, 15, 16, 15, 0, -15}, // 0x4C 'L' 203 | {851, 19, 16, 21, 1, -15}, // 0x4D 'M' 204 | {889, 16, 16, 17, 1, -15}, // 0x4E 'N' 205 | {921, 15, 16, 17, 1, -15}, // 0x4F 'O' 206 | {951, 12, 16, 14, 0, -15}, // 0x50 'P' 207 | {975, 16, 20, 17, 1, -15}, // 0x51 'Q' 208 | {1015, 15, 16, 16, 0, -15}, // 0x52 'R' 209 | {1045, 11, 16, 13, 0, -15}, // 0x53 'S' 210 | {1067, 15, 16, 15, 0, -15}, // 0x54 'T' 211 | {1097, 16, 16, 17, 1, -15}, // 0x55 'U' 212 | {1129, 17, 16, 17, 0, -15}, // 0x56 'V' 213 | {1163, 22, 16, 23, 0, -15}, // 0x57 'W' 214 | {1207, 17, 16, 17, 0, -15}, // 0x58 'X' 215 | {1241, 16, 16, 17, 0, -15}, // 0x59 'Y' 216 | {1273, 14, 16, 15, 1, -15}, // 0x5A 'Z' 217 | {1301, 5, 20, 8, 2, -15}, // 0x5B '[' 218 | {1314, 7, 17, 7, 0, -16}, // 0x5C '\' 219 | {1329, 5, 20, 8, 1, -15}, // 0x5D ']' 220 | {1342, 10, 9, 11, 1, -15}, // 0x5E '^' 221 | {1354, 12, 1, 12, 0, 3}, // 0x5F '_' 222 | {1356, 5, 4, 6, 0, -15}, // 0x60 '`' 223 | {1359, 10, 11, 10, 1, -10}, // 0x61 'a' 224 | {1373, 10, 17, 12, 1, -16}, // 0x62 'b' 225 | {1395, 8, 11, 11, 1, -10}, // 0x63 'c' 226 | {1406, 10, 17, 12, 1, -16}, // 0x64 'd' 227 | {1428, 10, 11, 11, 1, -10}, // 0x65 'e' 228 | {1442, 9, 17, 9, 0, -16}, // 0x66 'f' 229 | {1462, 12, 16, 11, 0, -10}, // 0x67 'g' 230 | {1486, 11, 17, 12, 0, -16}, // 0x68 'h' 231 | {1510, 5, 16, 7, 0, -15}, // 0x69 'i' 232 | {1520, 6, 21, 8, 0, -15}, // 0x6A 'j' 233 | {1536, 11, 17, 12, 1, -16}, // 0x6B 'k' 234 | {1560, 5, 17, 6, 0, -16}, // 0x6C 'l' 235 | {1571, 18, 11, 19, 0, -10}, // 0x6D 'm' 236 | {1596, 11, 11, 12, 0, -10}, // 0x6E 'n' 237 | {1612, 10, 11, 12, 1, -10}, // 0x6F 'o' 238 | {1626, 11, 16, 12, 0, -10}, // 0x70 'p' 239 | {1648, 10, 16, 12, 1, -10}, // 0x71 'q' 240 | {1668, 8, 11, 8, 0, -10}, // 0x72 'r' 241 | {1679, 7, 11, 9, 1, -10}, // 0x73 's' 242 | {1689, 6, 13, 7, 1, -12}, // 0x74 't' 243 | {1699, 10, 11, 12, 1, -10}, // 0x75 'u' 244 | {1713, 11, 11, 11, 0, -10}, // 0x76 'v' 245 | {1729, 16, 11, 16, 0, -10}, // 0x77 'w' 246 | {1751, 11, 11, 12, 0, -10}, // 0x78 'x' 247 | {1767, 11, 16, 11, 0, -10}, // 0x79 'y' 248 | {1789, 10, 11, 10, 0, -10}, // 0x7A 'z' 249 | {1803, 5, 21, 12, 2, -16}, // 0x7B '{' 250 | {1817, 1, 17, 5, 2, -16}, // 0x7C '|' 251 | {1820, 5, 21, 12, 5, -15}, // 0x7D '}' 252 | {1834, 12, 3, 12, 0, -6}}; // 0x7E '~' 253 | 254 | const GFXfont FreeSerif12pt7b PROGMEM = {(uint8_t *)FreeSerif12pt7bBitmaps, 255 | (GFXglyph *)FreeSerif12pt7bGlyphs, 256 | 0x20, 0x7E, 29}; 257 | 258 | // Approx. 2511 bytes 259 | -------------------------------------------------------------------------------- /examples/prop_font_demo/prop_font_demo.ino: -------------------------------------------------------------------------------- 1 | // 2 | // OneBitDisplay library simple demo 3 | // 4 | // Demonstrates how to initialize and use a few functions of the library 5 | // If your MCU has enough RAM, enable the backbuffer to see a demonstration 6 | // of the speed difference between drawing directly on the display versus 7 | // deferred rendering, followed by a "dump" of the memory to the display 8 | // 9 | #include 10 | #include "FreeSerif12pt7b.h" 11 | 12 | static uint8_t ucBackBuffer[1024]; 13 | 14 | // Use -1 for the Wire library default pins 15 | // or specify the pin numbers to use with the Wire library or bit banging on any GPIO pins 16 | // These are the pin numbers for the M5Stack Atom Grove port I2C (reversed SDA/SCL for straight through wiring) 17 | #define SDA_PIN 32 18 | #define SCL_PIN 26 19 | // Set this to -1 to disable or the GPIO pin number connected to the reset 20 | // line of your display if it requires an external reset 21 | #define RESET_PIN -1 22 | // let OneBitDisplay figure out the display address 23 | #define OLED_ADDR -1 24 | // don't rotate the display 25 | #define FLIP180 0 26 | // don't invert the display 27 | #define INVERT 0 28 | // Bit-Bang the I2C bus 29 | #define USE_HW_I2C 1 30 | 31 | // Change these if you're using a different OLED display 32 | #define MY_OLED OLED_128x64 33 | #define OLED_WIDTH 128 34 | #define OLED_HEIGHT 64 35 | //#define MY_OLED OLED_64x32 36 | //#define OLED_WIDTH 64 37 | //#define OLED_HEIGHT 32 38 | 39 | OBDISP obd; 40 | 41 | void setup() { 42 | int rc; 43 | // The I2C SDA/SCL pins set to -1 means to use the default Wire library 44 | // If pins were specified, they would be bit-banged in software 45 | // This isn't inferior to hw I2C and in fact allows you to go faster on certain CPUs 46 | // The reset pin is optional and I've only seen it needed on larger OLEDs (2.4") 47 | // that can be configured as either SPI or I2C 48 | // 49 | // obdI2CInit(OBDISP *, type, oled_addr, rotate180, invert, bWire, SDA_PIN, SCL_PIN, RESET_PIN, speed) 50 | 51 | rc = obdI2CInit(&obd, MY_OLED, OLED_ADDR, FLIP180, INVERT, USE_HW_I2C, SDA_PIN, SCL_PIN, RESET_PIN, 800000L); // use standard I2C bus at 400Khz 52 | if (rc != OLED_NOT_FOUND) 53 | { 54 | char *msgs[] = {(char *)"SSD1306 @ 0x3C", (char *)"SSD1306 @ 0x3D",(char *)"SH1106 @ 0x3C",(char *)"SH1106 @ 0x3D"}; 55 | obdFill(&obd, OBD_WHITE, 1); 56 | obdWriteString(&obd, 0,0,0,msgs[rc], FONT_8x8, OBD_BLACK, 1); 57 | obdSetBackBuffer(&obd, ucBackBuffer); 58 | delay(2000); 59 | } 60 | } /* setup() */ 61 | 62 | void loop() { 63 | int y; 64 | char szTemp[32]; 65 | unsigned long ms; 66 | 67 | obdFill(&obd, OBD_WHITE, 0); 68 | ms = micros(); 69 | obdWriteStringCustom(&obd, (GFXfont *)&FreeSerif12pt7b, 0, 16, (char *)"Hello World",OBD_BLACK); 70 | obdWriteStringCustom(&obd, (GFXfont *)&FreeSerif12pt7b, 0, 16+FreeSerif12pt7b.yAdvance, (char *)"Fast Perf!", OBD_BLACK); 71 | ms = micros() - ms; 72 | obdDumpBuffer(&obd, NULL); 73 | sprintf(szTemp, "rendered in %d us", (int)ms); 74 | obdWriteString(&obd, 0,0,7,szTemp, FONT_6x8, OBD_BLACK, 1); 75 | delay(4000); 76 | 77 | for (y=-30; y<80; y++) 78 | { 79 | obdFill(&obd, OBD_BLACK, 0); 80 | obdWriteStringCustom(&obd, (GFXfont *)&FreeSerif12pt7b, 0, y, (char *)"Hello World", OBD_WHITE); 81 | obdWriteStringCustom(&obd, (GFXfont *)&FreeSerif12pt7b, 0, y+FreeSerif12pt7b.yAdvance, (char *)"Fast Perf!", OBD_WHITE); 82 | obdDumpBuffer(&obd, NULL); 83 | } 84 | for (y=79; y>=-30; y--) 85 | { 86 | obdFill(&obd, OBD_WHITE, 0); 87 | obdWriteStringCustom(&obd, (GFXfont *)&FreeSerif12pt7b, 0, y, (char *)"Hello World", OBD_BLACK); 88 | obdWriteStringCustom(&obd, (GFXfont *)&FreeSerif12pt7b, 0, y+FreeSerif12pt7b.yAdvance, (char *)"Fast Perf!", OBD_BLACK); 89 | obdDumpBuffer(&obd, NULL); 90 | } 91 | } /* loop() */ 92 | -------------------------------------------------------------------------------- /examples/sharp_memory_lcd/sharp_memory_lcd.ino: -------------------------------------------------------------------------------- 1 | // Sharp Memory LCD (144x168) 2 | 3 | #include 4 | 5 | OBDISP obd; 6 | #define FLIP180 0 7 | #define INVERT 0 8 | #define BITBANG 0 9 | #define DC_PIN -1 10 | #define CS_PIN 10 11 | #define RESET_PIN -1 12 | #define MOSI_PIN -1 13 | #define CLK_PIN -1 14 | #define LED_PIN -1 15 | uint8_t ucBackBuf[400*240/8]; 16 | 17 | void setup() { 18 | obdSPIInit(&obd, SHARP_400x240, DC_PIN, CS_PIN, RESET_PIN, MOSI_PIN, CLK_PIN, LED_PIN, FLIP180, INVERT, BITBANG, 8000000L); 19 | obdSetBackBuffer(&obd, ucBackBuf); 20 | obdFill(&obd, OBD_WHITE, 0); 21 | obdWriteString(&obd,0,0,0,(char *)"Sharp Memory LCD Demo!", FONT_16x16, OBD_BLACK, 0); 22 | obdDumpBuffer(&obd, NULL); 23 | } 24 | 25 | void loop() { 26 | int i; 27 | 28 | while (1) 29 | { 30 | for (i=1; i<100; i++) 31 | { 32 | obdEllipse(&obd, 200, 140, i, i, OBD_BLACK, 0); // circle, not filled 33 | obdDumpBuffer(&obd, NULL); 34 | } 35 | for (i=99; i>=1; i--) 36 | { 37 | obdEllipse(&obd, 200, 140, i, i, OBD_WHITE, 0); // circle, not filled 38 | obdDumpBuffer(&obd, NULL); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /examples/simple_demo/simple_demo.ino: -------------------------------------------------------------------------------- 1 | // 2 | // OneBitDisplay library simple demo 3 | // 4 | // Demonstrates how to initialize and use a few functions of the library 5 | // If your MCU has enough RAM, enable the backbuffer to see a demonstration 6 | // of the speed difference between drawing directly on the display versus 7 | // deferred rendering, followed by a "dump" of the memory to the display 8 | // 9 | #include 10 | 11 | // if your system doesn't have enough RAM for a back buffer, comment out 12 | // this line (e.g. ATtiny85) 13 | #define USE_BACKBUFFER 14 | 15 | #ifdef USE_BACKBUFFER 16 | static uint8_t ucBackBuffer[1024]; 17 | #else 18 | static uint8_t *ucBackBuffer = NULL; 19 | #endif 20 | 21 | // Use -1 for the Wire library default pins 22 | // or specify the pin numbers to use with the Wire library or bit banging on any GPIO pins 23 | // These are the pin numbers for the M5Stack Atom Grove port I2C (reversed SDA/SCL for straight through wiring) 24 | #define SDA_PIN -1 25 | #define SCL_PIN -1 26 | //#define SDA_PIN 32 27 | //#define SCL_PIN 26 28 | // Set this to -1 to disable or the GPIO pin number connected to the reset 29 | // line of your display if it requires an external reset 30 | #define RESET_PIN -1 31 | // let OneBitDisplay figure out the display address 32 | #define OLED_ADDR -1 33 | // don't rotate the display 34 | #define FLIP180 0 35 | // don't invert the display 36 | #define INVERT 0 37 | // Bit-Bang the I2C bus 38 | #define USE_HW_I2C 1 39 | 40 | // Change these if you're using a different OLED display 41 | #define MY_OLED OLED_128x64 42 | #define OLED_WIDTH 128 43 | #define OLED_HEIGHT 64 44 | //#define MY_OLED OLED_64x32 45 | //#define OLED_WIDTH 64 46 | //#define OLED_HEIGHT 32 47 | 48 | OBDISP obd; 49 | 50 | void setup() { 51 | int rc; 52 | // The I2C SDA/SCL pins set to -1 means to use the default Wire library 53 | // If pins were specified, they would be bit-banged in software 54 | // This isn't inferior to hw I2C and in fact allows you to go faster on certain CPUs 55 | // The reset pin is optional and I've only seen it needed on larger OLEDs (2.4") 56 | // that can be configured as either SPI or I2C 57 | // 58 | // obdI2CInit(OBDISP *, type, oled_addr, rotate180, invert, bWire, SDA_PIN, SCL_PIN, RESET_PIN, speed) 59 | 60 | rc = obdI2CInit(&obd, MY_OLED, OLED_ADDR, FLIP180, INVERT, USE_HW_I2C, SDA_PIN, SCL_PIN, RESET_PIN, 400000L); // use standard I2C bus at 400Khz 61 | if (rc != OLED_NOT_FOUND) 62 | { 63 | char *msgs[] = {(char *)"SSD1306 @ 0x3C", (char *)"SSD1306 @ 0x3D",(char *)"SH1106 @ 0x3C",(char *)"SH1106 @ 0x3D"}; 64 | obdFill(&obd, OBD_WHITE, 1); 65 | obdWriteString(&obd, 0,0,0,msgs[rc], FONT_8x8, OBD_BLACK, 1); 66 | obdSetBackBuffer(&obd, ucBackBuffer); 67 | delay(2000); 68 | } 69 | } /* setup() */ 70 | 71 | void loop() { 72 | // put your main code here, to run repeatedly: 73 | int i, x, y; 74 | char szTemp[32]; 75 | unsigned long ms; 76 | 77 | obdFill(&obd, OBD_WHITE, 1); 78 | obdWriteString(&obd, 0,28,0,(char *)"OLED Demo", FONT_8x8, OBD_BLACK, 1); 79 | obdWriteString(&obd, 0,0,8,(char *)"Written by Larry Bank", FONT_6x8, OBD_WHITE, 1); 80 | obdWriteString(&obd, 0,0,24,(char *)"**Demo**", FONT_16x32, OBD_BLACK, 1); 81 | delay(2000); 82 | 83 | // Pixel and line functions won't work without a back buffer 84 | #ifdef USE_BACKBUFFER 85 | obdFill(&obd, OBD_WHITE, 1); 86 | obdWriteString(&obd, 0,0,0,(char *)"Backbuffer Test", FONT_8x8,OBD_BLACK,1); 87 | obdWriteString(&obd, 0,0,8,(char *)"3000 Random dots", FONT_8x8,OBD_BLACK,1); 88 | delay(2000); 89 | obdFill(&obd, OBD_WHITE,1); 90 | ms = millis(); 91 | for (i=0; i<3000; i++) 92 | { 93 | x = random(OLED_WIDTH); 94 | y = random(OLED_HEIGHT); 95 | obdSetPixel(&obd, x, y, 1, 1); 96 | } 97 | ms = millis() - ms; 98 | sprintf(szTemp, "%dms", (int)ms); 99 | obdWriteString(&obd, 0,0,0,szTemp, FONT_8x8, OBD_BLACK, 1); 100 | obdWriteString(&obd, 0,0,8,(char *)"Without backbuffer", FONT_6x8,OBD_BLACK,1); 101 | delay(2000); 102 | obdFill(&obd, OBD_WHITE,1); 103 | ms = millis(); 104 | for (i=0; i<3000; i++) 105 | { 106 | x = random(OLED_WIDTH); 107 | y = random(OLED_HEIGHT); 108 | obdSetPixel(&obd, x, y, 1, 0); 109 | } 110 | obdDumpBuffer(&obd, NULL); 111 | ms = millis() - ms; 112 | sprintf(szTemp, "%dms", (int)ms); 113 | obdWriteString(&obd, 0,0,0,szTemp, FONT_8x8, OBD_BLACK, 1); 114 | obdWriteString(&obd, 0,0,8,(char *)"With backbuffer", FONT_6x8,OBD_BLACK,1); 115 | delay(2000); 116 | obdFill(&obd, OBD_WHITE, 1); 117 | obdWriteString(&obd, 0,0,0,(char *)"Backbuffer Test", FONT_8x8,OBD_BLACK,1); 118 | obdWriteString(&obd, 0,0,8,(char *)"96 lines", FONT_8x8,OBD_BLACK,1); 119 | delay(2000); 120 | ms = millis(); 121 | for (x=0; x 6 | 7 | OBDISP obd; 8 | #define SDA_PIN -1 9 | #define SCL_PIN -1 10 | // no reset pin needed 11 | #define RESET_PIN -1 12 | // let OneBitDisplay find the address of our display 13 | #define OLED_ADDR -1 14 | #define FLIP180 0 15 | #define INVERT 0 16 | // Use the default Wire library 17 | #define USE_HW_I2C 1 18 | void setup() 19 | { 20 | int rc; 21 | rc = obdI2CInit(&obd, OLED_128x64, OLED_ADDR, FLIP180, INVERT, USE_HW_I2C, SDA_PIN, SCL_PIN, RESET_PIN, 400000L); // Standard HW I2C bus at 400Khz 22 | 23 | if (rc != OLED_NOT_FOUND) 24 | { 25 | char *msgs[] = 26 | { 27 | (char *)"SSD1306 @ 0x3C", 28 | (char *)"SSD1306 @ 0x3D", 29 | (char *)"SH1106 @ 0x3C", 30 | (char *)"SH1106 @ 0x3D" 31 | }; 32 | 33 | obdFill(&obd, 0, 1); 34 | obdWriteString(&obd, 0, 0, 0, (char *)"OLED found:", FONT_8x8, 0, 1); 35 | obdWriteString(&obd, 0, 10, 2, msgs[rc], FONT_8x8, 0, 1); 36 | delay(3000); 37 | } 38 | } 39 | 40 | void loop() 41 | { 42 | int i, x, y; 43 | 44 | obdFill(&obd, 0, 1); 45 | obdWriteString(&obd, 0, 28, 0,(char *)"OLED Demo", FONT_8x8, 0, 1); 46 | obdWriteString(&obd, 0, 0, 1,(char *)"Written by Larry Bank", FONT_6x8, 1, 1); 47 | obdWriteString(&obd, 0, 0, 3,(char *)"**Demo**", FONT_16x16, 0, 1); 48 | obdWriteString(&obd, 0, 9, 6,(char *)"for AVR", FONT_16x16, 0, 1); 49 | 50 | delay(2000); 51 | obdFill(&obd, 0, 1); 52 | 53 | for (i = 0; i < 1000; i++) 54 | { 55 | x = random(128); 56 | y = random(64); 57 | obdSetPixel(&obd, x, y, 1, 1); 58 | } 59 | 60 | delay(2000); 61 | } 62 | -------------------------------------------------------------------------------- /examples/tiff_on_avr/bart_1bpp.h: -------------------------------------------------------------------------------- 1 | // 2 | // bart_1bpp 3 | // Data size = 860 bytes 4 | // 5 | // TIFF, Compression=G4, Size: 104 x 285, 1-Bpp 6 | // 7 | // for non-Arduino builds... 8 | #ifndef PROGMEM 9 | #define PROGMEM 10 | #endif 11 | const uint8_t bart_1bpp[] PROGMEM = { 12 | 0x4d,0x4d,0x00,0x2a,0x00,0x00,0x02,0xba,0x26,0xa0,0x78,0x36,0x7f,0xff,0xc8,0x35, 13 | 0x0e,0x41,0x81,0xf2,0x0d,0xdd,0x48,0xae,0x9f,0x76,0xbe,0x41,0x07,0xb4,0xd3,0x52, 14 | 0x4f,0xda,0xfa,0x69,0x92,0x7e,0xed,0x34,0xf5,0x5e,0xd3,0x8d,0x57,0xee,0x26,0x11, 15 | 0x9a,0x13,0x09,0xda,0x92,0x1f,0x89,0x8e,0xd6,0xc6,0x9a,0xea,0xd3,0x4d,0x4f,0x7d, 16 | 0x3e,0x6d,0x27,0xea,0xa3,0x5f,0x7a,0x69,0xa7,0x67,0x97,0x22,0x8f,0xee,0xe3,0xd7, 17 | 0x1a,0xfb,0x42,0x35,0x58,0x5f,0x11,0x6a,0x79,0x57,0xaa,0x6a,0xc2,0x5f,0xf1,0xf8, 18 | 0xd7,0xf4,0xce,0x25,0xe3,0x5f,0xc2,0x5f,0x1f,0xeb,0xd7,0x5f,0xeb,0xff,0x5f,0xfe, 19 | 0xbf,0xff,0xa5,0xfa,0xff,0xff,0x5f,0xfe,0xbf,0xff,0x55,0xfa,0xff,0xff,0x5f,0xff, 20 | 0xd6,0xb4,0xbd,0x2f,0xa2,0x0d,0x23,0xaf,0x44,0xfc,0x86,0x08,0xfc,0x10,0x30,0x41, 21 | 0xfc,0x43,0x41,0xd7,0x27,0x98,0x46,0x62,0xbf,0x9e,0x08,0xd0,0x20,0xdf,0xd0,0x62, 22 | 0x10,0x6d,0x74,0x13,0x4d,0xfa,0x4d,0x3f,0xf4,0xdd,0x69,0x53,0xfe,0xb7,0xe9,0x53, 23 | 0xfe,0x44,0xce,0xff,0x4d,0x75,0xeb,0xa2,0x0b,0xdb,0xff,0xe9,0xff,0xfa,0x7f,0xdf, 24 | 0xfd,0x7b,0x5f,0xfe,0x3d,0x7e,0xe5,0x91,0x6d,0x2f,0xda,0x18,0xfe,0xc7,0x5f,0x33, 25 | 0x1b,0x5f,0x61,0x10,0xc5,0xeb,0xbb,0x69,0x7d,0x36,0x95,0xfd,0xa8,0x4f,0xb6,0xd2, 26 | 0x4f,0xdb,0x4a,0x6f,0x7d,0xb0,0x60,0x94,0x20,0xfd,0xb1,0x42,0x55,0x39,0x38,0x30, 27 | 0x12,0xf3,0x50,0x20,0x4b,0xcc,0x6c,0x82,0xf9,0xf8,0x34,0x33,0xeb,0xe2,0x0f,0xfb, 28 | 0x4b,0xa8,0x7f,0x20,0x51,0x69,0x75,0x15,0xed,0x6a,0x18,0x5e,0xd7,0x5f,0xde,0xbf, 29 | 0xfd,0x7d,0x90,0x57,0xcf,0xb0,0x9f,0xb0,0xc2,0x6f,0xb6,0x11,0x9a,0xf8,0x60,0xc8, 30 | 0x34,0x1d,0xfd,0x83,0x20,0xdc,0x31,0xf0,0xc4,0x2f,0x06,0x44,0x80,0xbf,0x06,0x49, 31 | 0x86,0x67,0x20,0xdf,0x5b,0xc8,0x69,0x67,0xb3,0x30,0xcd,0xed,0xde,0xdd,0xe0,0xeb, 32 | 0x86,0xc2,0x7e,0x83,0xdc,0x20,0xfc,0x13,0xf2,0x09,0xa9,0x3c,0xd0,0x84,0x1b,0xd1, 33 | 0x50,0x93,0x7a,0x25,0xcd,0x37,0xa3,0x81,0xb1,0x37,0xaa,0x5e,0xbb,0x7d,0x25,0xeb, 34 | 0xbe,0xa9,0x5e,0x96,0xfc,0xda,0xd7,0xa4,0xbd,0xfe,0xbe,0x95,0x6f,0xd7,0x5e,0xab, 35 | 0xff,0xfe,0x97,0xff,0x4b,0xfa,0xc9,0x3f,0xb1,0xc5,0xef,0xf5,0x33,0x07,0xfb,0x87, 36 | 0xf0,0x78,0x5a,0xf5,0xff,0xcc,0x25,0xaf,0xff,0xc7,0xfa,0xd7,0xff,0xcc,0x2f,0xff, 37 | 0xfc,0x57,0xff,0x7a,0xf3,0x09,0xf5,0xf7,0xd7,0xbf,0x5e,0xdf,0x5e,0xff,0xf7,0xa4, 38 | 0xbb,0x7d,0x6b,0xeb,0xed,0xf5,0xfe,0xbe,0xfd,0x55,0x5e,0xbe,0xff,0xf7,0xd7,0xfa, 39 | 0xfb,0xfe,0xb7,0xd2,0xff,0xfb,0xeb,0xff,0xf5,0x7f,0x5f,0xfe,0xfd,0x7f,0xde,0xbf, 40 | 0x0d,0x7b,0xd9,0x40,0x65,0x7f,0x65,0x40,0x7d,0x7b,0x15,0x1e,0xcd,0xaf,0xb9,0x0e, 41 | 0x0f,0xec,0x86,0x55,0x10,0x2d,0xbb,0x9b,0x0b,0xf9,0x88,0x3a,0xfb,0xd8,0x3d,0x2d, 42 | 0x3c,0x30,0x7d,0x77,0x86,0x35,0xef,0x0c,0x34,0xbb,0xc1,0xb5,0xe6,0xd3,0xc8,0x11, 43 | 0xc9,0x78,0x6e,0xc6,0xbd,0x87,0xd7,0xb6,0xff,0xb0,0xef,0xf0,0xc3,0x6f,0xf6,0x0e, 44 | 0xff,0x0c,0xa0,0x7f,0xc1,0x86,0x3f,0x61,0xfd,0x86,0x41,0x8b,0xf6,0x0f,0xf6,0x3f, 45 | 0x0e,0x17,0x21,0xaa,0x20,0x17,0x06,0x41,0x83,0x0b,0x98,0x08,0x21,0x78,0x64,0x0c, 46 | 0x33,0xf6,0x61,0x12,0xe0,0xa3,0xf3,0x60,0x9f,0xfa,0xff,0xff,0xff,0xff,0xf7,0xff, 47 | 0xff,0xff,0xff,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd7,0xfd,0x06,0xbf, 48 | 0xa1,0xfe,0x9f,0xf3,0x77,0xfc,0x8a,0xe4,0xa7,0xe1,0x06,0x28,0x19,0x29,0xe8,0x86, 49 | 0x43,0xd1,0xc4,0x2f,0x09,0x06,0x6b,0x46,0x19,0x47,0xd0,0x44,0x25,0x62,0xba,0x40, 50 | 0xc1,0x84,0xf4,0xa6,0xe1,0xf5,0x48,0xf2,0x23,0x13,0xd2,0xd0,0x41,0x84,0xfa,0x5a, 51 | 0x44,0x3d,0xde,0x94,0x50,0xbf,0xb5,0x7a,0x55,0xe9,0x24,0xfc,0x3a,0xf4,0x0d,0x2b, 52 | 0xe5,0x3b,0x4f,0xcc,0x21,0xfd,0x96,0x30,0x27,0xc1,0x91,0x86,0x0b,0xca,0x02,0x9a, 53 | 0x03,0x7e,0x18,0x9d,0x45,0x29,0xd3,0xc1,0x88,0x55,0x90,0x68,0xa8,0xc0,0x40,0xb9, 54 | 0x0d,0x64,0x12,0xac,0x17,0x21,0xb6,0x71,0x31,0x1b,0x10,0x58,0x30,0x58,0x32,0x90, 55 | 0x32,0xe4,0x16,0x03,0xc7,0xff,0xfe,0x00,0x20,0x02,0x00,0x0d,0x01,0x00,0x00,0x03, 56 | 0x00,0x00,0x00,0x01,0x00,0x68,0x00,0x00,0x01,0x01,0x00,0x03,0x00,0x00,0x00,0x01, 57 | 0x01,0x1d,0x00,0x00,0x01,0x02,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00, 58 | 0x01,0x03,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x00,0x01,0x06,0x00,0x03, 59 | 0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x01,0x0a,0x00,0x03,0x00,0x00,0x00,0x01, 60 | 0x00,0x01,0x00,0x00,0x01,0x11,0x00,0x04,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x08, 61 | 0x01,0x12,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x01,0x15,0x00,0x03, 62 | 0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x01,0x16,0x00,0x03,0x00,0x00,0x00,0x01, 63 | 0x01,0x1d,0x00,0x00,0x01,0x17,0x00,0x04,0x00,0x00,0x00,0x01,0x00,0x00,0x02,0xb2, 64 | 0x01,0x1c,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x01,0x29,0x00,0x03, 65 | 0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00}; 66 | -------------------------------------------------------------------------------- /examples/tiff_on_avr/tiff_on_avr.ino: -------------------------------------------------------------------------------- 1 | // 2 | // This demo sketch shows something that's normally very challenging 3 | // to accomplish on a resource-constrained 8-bit MCU (Arduino Uno) 4 | // The sketch has 2 TIFF G4 images (1-bit highly compressed) 5 | // stored in FLASH that are decoded directly into the e-paper's 6 | // frame buffer. This allows this particular demo to work with images 7 | // that normally would not fit in the available RAM (2K). One limitation 8 | // of this method is that the image can only be written in the native 9 | // memory direction of the e-paper panel. In this case, the 128x296 EPD 10 | // is oriented with the bytes in portrait orientation, MSB on the left. 11 | // 12 | // The G4 library has size limits imposed (200 pixels wide by N tall) to be 13 | // able to use only 1K of RAM to accomplish this task. The OneBitDisplay 14 | // library includes code specifically to allow working with e-paper 15 | // displays without a local buffer to hold the pixels 16 | // 17 | // If you disable the Serial print statements, there will be 18 | // plenty of FLASH space left on the UNO to hold other code/data 19 | // 20 | // Written by Larry Bank Oct 13, 2022 21 | // 22 | #include 23 | #include 24 | #include "uno_bw.h" 25 | #include "bart_1bpp.h" 26 | 27 | ONE_BIT_DISPLAY obd; 28 | TIFFG4 tiff; 29 | 30 | // 31 | // These defines are for the Waveshare Arduino UNO e-paper shield 32 | // please change them to suit your hardware 33 | // 34 | #define EPD_FREQ 2000000 35 | #define EPD_CS 10 36 | #define EPD_DC 9 37 | #define EPD_BUSY 7 38 | #define EPD_RES 8 39 | // Values of -1 here indicate that the default system pin numbers should be used 40 | #define EPD_MOSI -1 41 | #define EPD_SCK -1 42 | // This is a 2.9" 128x296 e-paper with the SSD16xx controller chip 43 | // The panel I used for this demo has "HINK-E029A27-A0" 44 | #define EPD_TYPE EPD293_128x296 45 | 46 | // This is the callback function you write to receive each line 47 | // of decoded pixels as they're being decoded 48 | void TIFFDraw(TIFFDRAW *pDraw) 49 | { 50 | // Serial.print("TIFFDraw line = "); 51 | // Serial.println(pDraw->y, DEC); 52 | if (pDraw->y == 0) { // When you receive the first line, you can set the memory window parameters for the e-paper 53 | obd.setPosition(0, 0, tiff.getWidth(), tiff.getHeight()); 54 | } 55 | // invert the pixels for EPD (black = 1) 56 | for (int i=0; i<(pDraw->iWidth/8); i++) { 57 | pDraw->pPixels[i] = ~pDraw->pPixels[i]; 58 | } 59 | obd.pushPixels((uint8_t *)pDraw->pPixels, (pDraw->iWidth/8)); // send this line of pixels to the EPD; the destination address will automatically increment 60 | } /* TIFFDraw() */ 61 | 62 | void setup() { 63 | Serial.begin(115200); 64 | Serial.println("Starting"); 65 | obd.setSPIPins(EPD_CS, EPD_MOSI, EPD_SCK, EPD_DC, EPD_RES, EPD_BUSY); 66 | obd.SPIbegin(EPD_TYPE, EPD_FREQ); // initialize OneBitDisplay for this e-paper panel 67 | } /* setup() */ 68 | 69 | // 70 | // This function will decode a TIFF image that is stored in FLASH 71 | // given the starting offset and size of the data 72 | // 73 | void decodeImage(const uint8_t *pData, size_t size) 74 | { 75 | if (tiff.openTIFF((uint8_t *)pData, (int)size, TIFFDraw)) 76 | { 77 | Serial.print("TIFF opened, size = "); 78 | Serial.print(tiff.getWidth(), DEC); 79 | Serial.print("x"); 80 | Serial.println(tiff.getHeight(), DEC); 81 | tiff.decode(); 82 | tiff.close(); 83 | Serial.println("Finished decoding"); 84 | } else { 85 | Serial.print("Error opening TIFF = "); 86 | Serial.println(tiff.getLastError(), DEC); 87 | } 88 | } /* decodeImage() */ 89 | 90 | void loop() { 91 | 92 | obd.fillScreen(OBD_WHITE); // clear the EPD's internal RAM to white 93 | obd.setTextColor(OBD_BLACK, OBD_WHITE); // use the correct EPD memory plane (0) 94 | decodeImage(uno_bw, sizeof(uno_bw)); 95 | obd.display(); // this causes the EPD to do a full refresh 96 | obd.fillScreen(OBD_WHITE); // prepare the second image by clearing the EPD memory to white again 97 | decodeImage(bart_1bpp, sizeof(bart_1bpp)); 98 | obd.display(); // show the Bart image 99 | obd.fillScreen(OBD_WHITE); 100 | obd.display(); // finish by clearing the EPD to white again 101 | while (1) 102 | {}; 103 | } /* loop() */ 104 | -------------------------------------------------------------------------------- /examples/tiff_on_avr/uno_bw.h: -------------------------------------------------------------------------------- 1 | // 2 | // uno_bw 3 | // Data size = 532 bytes 4 | // 5 | // TIFF, Compression=G4, Size: 128 x 166, 1-Bpp 6 | // 7 | // for non-Arduino builds... 8 | #ifndef PROGMEM 9 | #define PROGMEM 10 | #endif 11 | const uint8_t uno_bw[] PROGMEM = { 12 | 0x4d,0x4d,0x00,0x2a,0x00,0x00,0x01,0x72,0x26,0xa1,0x90,0x1b,0xff,0xf2,0x07,0x85, 13 | 0x07,0xae,0x9f,0xff,0xff,0xe4,0x36,0x69,0xe1,0x07,0xf7,0xff,0xff,0xf9,0x09,0xd9, 14 | 0x80,0xf3,0x27,0xd3,0xd3,0xd3,0xd7,0x5d,0x7f,0xff,0xf7,0xdf,0xae,0xbf,0xf6,0xb0, 15 | 0xff,0x8e,0x43,0x1f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff, 16 | 0xd7,0xfb,0x5f,0xe3,0xff,0xff,0xfd,0x7e,0xd7,0xe3,0xff,0xff,0xff,0xff,0xff,0xff, 17 | 0xff,0xff,0xff,0xff,0xe4,0x0f,0x0d,0xd1,0xf8,0x41,0xfe,0x9f,0xe9,0xfe,0x9f,0xe8, 18 | 0x9e,0x7f,0xa0,0x40,0xdf,0xf0,0x83,0xfe,0x93,0x7f,0xff,0xf4,0xdf,0xea,0x47,0x1f, 19 | 0xfe,0xff,0x90,0xcf,0xa7,0xff,0xa7,0xff,0xff,0xff,0x82,0x23,0xf3,0x8f,0xff,0xe1, 20 | 0x3d,0x07,0xeb,0xff,0xff,0xff,0xf4,0xdf,0xfe,0x38,0xe2,0x97,0xfd,0xff,0x90,0x4b, 21 | 0xca,0xb7,0x4b,0xff,0xed,0x7f,0xfa,0x6d,0x2f,0xc7,0x16,0x1a,0xff,0xb6,0x12,0xfc, 22 | 0x82,0x5e,0x55,0xc5,0x7f,0xf8,0x6b,0xff,0xd8,0x5f,0x8e,0x2d,0x7f,0x84,0x1f,0xe4, 23 | 0x12,0xf2,0xad,0x3f,0xff,0x4f,0xff,0xd1,0xa4,0xff,0x1c,0x50,0x41,0xbf,0xfa,0x7f, 24 | 0xc8,0x25,0xe5,0x42,0x4d,0xff,0xf7,0x4f,0xff,0xe9,0x37,0xfb,0x5b,0x5f,0xf8,0xe3, 25 | 0x44,0x70,0xdf,0xe4,0x1d,0xf2,0xa1,0x7f,0xf4,0xfb,0xf7,0xff,0xfc,0x10,0x3f,0xf6, 26 | 0xba,0xff,0xf1,0xc7,0xff,0xc8,0x3b,0xe5,0x46,0x0c,0x17,0xfa,0x7d,0xfa,0xff,0xff, 27 | 0xff,0xb5,0xd3,0x63,0x5f,0x8e,0x3a,0xfe,0x41,0xdf,0x2a,0x1b,0x5f,0xd3,0xee,0xd2, 28 | 0xff,0xf6,0x18,0x4b,0xf6,0xba,0x63,0xfc,0x71,0xaf,0xc8,0x3b,0xe7,0x70,0xc2,0xfd, 29 | 0x3d,0x36,0xbf,0xfc,0x30,0xbf,0xfa,0x06,0x0b,0xf1,0xc4,0x7f,0xff,0x20,0x97,0x95, 30 | 0x7f,0xff,0xff,0xff,0x8e,0x3f,0xff,0x90,0x4b,0xca,0xbf,0xff,0xff,0xff,0xc7,0x1f, 31 | 0xff,0xc8,0x25,0xe5,0x47,0xff,0x7f,0xff,0xf8,0xe3,0xff,0xf9,0x04,0xbc,0xa8,0xff, 32 | 0xef,0xff,0xff,0x6b,0x6b,0xf1,0xc7,0xf2,0x0e,0xf9,0x51,0xfa,0x7d,0xff,0xcf,0x3f, 33 | 0xfb,0x54,0xf5,0xf8,0xf8,0xff,0x1f,0xf5,0xf8,0x90,0xda,0x02,0xf5,0xf0,0xbd,0xaf, 34 | 0x6b,0xb1,0x5b,0x5b,0x3b,0x4e,0x1a,0x76,0xb6,0xb6,0xb6,0xb1,0xff,0xe0,0x02,0x00, 35 | 0x20,0x00,0x00,0x0d,0x01,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x80,0x00,0x00, 36 | 0x01,0x01,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0xa6,0x00,0x00,0x01,0x02,0x00,0x03, 37 | 0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x01,0x03,0x00,0x03,0x00,0x00,0x00,0x01, 38 | 0x00,0x04,0x00,0x00,0x01,0x06,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00, 39 | 0x01,0x0a,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x01,0x11,0x00,0x04, 40 | 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x08,0x01,0x12,0x00,0x03,0x00,0x00,0x00,0x01, 41 | 0x00,0x01,0x00,0x00,0x01,0x15,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00, 42 | 0x01,0x16,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0xa6,0x00,0x00,0x01,0x17,0x00,0x04, 43 | 0x00,0x00,0x00,0x01,0x00,0x00,0x01,0x69,0x01,0x1c,0x00,0x03,0x00,0x00,0x00,0x01, 44 | 0x00,0x01,0x00,0x00,0x01,0x29,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x01, 45 | 0x00,0x00,0x00,0x00}; 46 | -------------------------------------------------------------------------------- /examples/uc1609_test/uc1609.h: -------------------------------------------------------------------------------- 1 | // 2 | // uc1609 3 | // 4 | const uint8_t uc1609[] PROGMEM = { 0x42,0x4d,0x82,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x82,0x00,0x00,0x00,0x6c,0x00, 5 | 0x00,0x00,0xc0,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00, 6 | 0x00,0x00,0x00,0x06,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00, 7 | 0x00,0x00,0x02,0x00,0x00,0x00,0x42,0x47,0x52,0x73,0x00,0x00,0x00,0x00,0x00,0x00, 8 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 9 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 10 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00, 11 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, 12 | 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00, 13 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 14 | 0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 15 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00, 16 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 17 | 0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 18 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00, 19 | 0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 20 | 0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xf0,0x00,0x00, 21 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00, 22 | 0x00,0x00,0x00,0x00,0x03,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 23 | 0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x00,0x00, 24 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00, 25 | 0x00,0x00,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xff,0xff,0xff, 26 | 0x00,0x18,0x00,0x07,0xf0,0x03,0xcf,0x1e,0x1e,0x0f,0x3c,0x3e,0xf0,0x1e,0x00,0x00, 27 | 0x00,0x00,0x00,0x00,0x1f,0xff,0xff,0xff,0x00,0x18,0x00,0x0f,0xfc,0x07,0xff,0x1e, 28 | 0x1e,0x3f,0xfc,0x7f,0xf0,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, 29 | 0x00,0x18,0x00,0x0f,0xfe,0x0f,0xff,0x1e,0x1e,0x3f,0xfc,0xff,0xf0,0x1f,0x00,0x00, 30 | 0x00,0x00,0x00,0x03,0xff,0xff,0xff,0xff,0x00,0x18,0x00,0x0c,0x1f,0x0f,0x1f,0x1e, 31 | 0x1e,0x7c,0x7c,0xf1,0xf0,0x3b,0x80,0x00,0x00,0x00,0x00,0x07,0xff,0xff,0xff,0xff, 32 | 0x00,0x18,0x00,0x00,0x0f,0x0f,0x1f,0x1e,0x1e,0x78,0x3c,0xf0,0xf0,0x3b,0x80,0x00, 33 | 0x00,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0x00,0x18,0x00,0x00,0x0f,0x0f,0x0f,0x1e, 34 | 0x1e,0x78,0x3c,0xf8,0xf0,0x7b,0x80,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xff, 35 | 0x00,0x18,0x00,0x00,0x1f,0x0f,0x0f,0x1e,0x1e,0x78,0x3c,0x7f,0xf0,0x71,0xc0,0x00, 36 | 0x00,0x00,0x00,0x7f,0xff,0xff,0xff,0xff,0x00,0x18,0x00,0x00,0xfe,0x0f,0x0f,0x1e, 37 | 0x1e,0x78,0x3c,0x1f,0xf0,0x71,0xc0,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff, 38 | 0x00,0x18,0x00,0x03,0xfe,0x0f,0x0f,0x1f,0x1e,0x78,0x3c,0x00,0xf0,0xf1,0xe0,0x00, 39 | 0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00,0x18,0x00,0x07,0xf8,0x0f,0x0f,0x1f, 40 | 0x1e,0x3c,0x3c,0x40,0xf0,0xe0,0xe0,0x00,0x00,0x00,0x01,0xff,0xff,0xff,0xff,0xff, 41 | 0x00,0x18,0x00,0x0f,0xc0,0x0f,0x0f,0x1f,0xfe,0x3f,0xfc,0x7f,0xf1,0xe0,0xe0,0x00, 42 | 0x00,0x00,0x03,0xff,0xff,0xff,0xff,0xff,0x00,0x18,0x00,0x0f,0x00,0x0f,0x0f,0x1f, 43 | 0xfc,0x1f,0xfc,0x7f,0xe1,0xe0,0xf0,0x00,0x00,0x00,0x03,0xff,0xff,0xff,0xff,0xff, 44 | 0x00,0x18,0x00,0x0f,0x00,0x0f,0x0f,0x1e,0xf8,0x07,0xfc,0x3f,0xc1,0xc0,0x70,0x00, 45 | 0x00,0x00,0x07,0xff,0xff,0xff,0xff,0xff,0x00,0x18,0x00,0x0f,0x82,0x00,0x00,0x00, 46 | 0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xff,0xff,0xff,0xff,0xff, 47 | 0x00,0x18,0x00,0x07,0xfe,0x00,0x00,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00, 48 | 0x00,0x00,0x07,0xff,0xff,0xff,0xff,0xff,0x00,0x18,0x00,0x07,0xfe,0x00,0x00,0x00, 49 | 0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xff, 50 | 0x00,0x18,0x00,0x01,0xfc,0x00,0x00,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00, 51 | 0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xff,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00, 52 | 0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xff, 53 | 0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 54 | 0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xff,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00, 55 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0xff, 56 | 0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 57 | 0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0xff,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00, 58 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0xff, 59 | 0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 60 | 0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0xff,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00, 61 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0xff, 62 | 0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 63 | 0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0xff,0x00,0x18,0x00,0x30,0x00,0x00,0x00,0x00, 64 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0xff, 65 | 0x00,0x18,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 66 | 0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0xff,0x00,0x18,0x00,0x30,0x00,0x00,0x00,0x00, 67 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0xff, 68 | 0x00,0x18,0x60,0x00,0x0c,0x00,0x00,0x01,0x80,0x00,0x00,0x00,0x00,0x03,0x80,0x00, 69 | 0x03,0x00,0x1f,0xff,0xff,0xff,0xff,0xfe,0x00,0x18,0x70,0x00,0x1c,0x03,0xff,0x8f, 70 | 0xf0,0x00,0x00,0x03,0xff,0x8f,0xe0,0x00,0x1f,0xe0,0x1f,0xff,0xff,0xff,0xff,0xfe, 71 | 0x00,0x18,0x20,0xfe,0x18,0x03,0xff,0x9f,0xf8,0x00,0x00,0x03,0xff,0x9f,0xf0,0x00, 72 | 0x3f,0xf0,0x1f,0xff,0xff,0xff,0xff,0xfe,0x00,0x18,0x03,0xff,0x00,0x01,0xe7,0x9c, 73 | 0x78,0x00,0x00,0x01,0xe7,0x0c,0x78,0x00,0x7c,0x70,0x1f,0xff,0xff,0xff,0xff,0xfc, 74 | 0x00,0x18,0x07,0xff,0xc0,0x00,0xf0,0x08,0x3c,0x00,0x00,0x00,0xf0,0x00,0x38,0x00, 75 | 0x78,0x20,0x1f,0xff,0xff,0xff,0xff,0xfc,0x00,0x18,0x0f,0xff,0xc0,0x00,0x78,0x00, 76 | 0x1c,0x00,0x00,0x00,0x78,0x00,0x38,0x00,0xf0,0x00,0x1f,0xff,0xff,0xff,0xff,0xf8, 77 | 0x00,0x18,0x1f,0xff,0xe0,0x00,0x3c,0x00,0x3c,0x00,0x1f,0x80,0x3c,0x00,0x1c,0x00, 78 | 0xe0,0x00,0x1f,0xff,0xff,0xff,0xff,0xf8,0x00,0x18,0x1f,0xff,0xe0,0x00,0x1c,0x00, 79 | 0x78,0x40,0x3f,0xc0,0x1c,0x07,0xdc,0x00,0xe0,0x00,0x1f,0xff,0xff,0xff,0xff,0xf0, 80 | 0x00,0x18,0x1f,0xff,0xf0,0x00,0x0e,0x03,0xf0,0xe0,0x7d,0xe0,0x1e,0x0f,0xfc,0x00, 81 | 0xe0,0x00,0x1f,0xff,0xff,0xff,0xff,0xe0,0x00,0x18,0x3f,0xff,0xf0,0x00,0x0f,0x03, 82 | 0xe0,0xf9,0xf0,0xf0,0x0e,0x1e,0x7c,0x00,0xe0,0x00,0x1f,0xff,0xff,0xff,0xff,0xc0, 83 | 0x00,0x1b,0xbf,0xff,0xf7,0x80,0x07,0x00,0xf0,0x7f,0xe0,0x60,0x07,0x1c,0x1c,0x00, 84 | 0xe0,0x00,0x1f,0xff,0xff,0xff,0xff,0x80,0x00,0x1b,0xbf,0xff,0xf3,0x00,0x07,0x00, 85 | 0x38,0x3f,0x80,0x00,0x07,0x1c,0x1c,0x78,0xe0,0x00,0x1f,0xff,0xff,0xff,0xff,0x00, 86 | 0x00,0x18,0x1f,0xff,0xf0,0x00,0x07,0x00,0x38,0x04,0x00,0x00,0x07,0x1c,0x38,0xfc, 87 | 0xf0,0x00,0x1f,0xff,0xff,0xff,0xfe,0x00,0x00,0x18,0x1f,0xff,0xf0,0x01,0x07,0x00, 88 | 0x38,0x00,0x00,0x01,0x07,0x1c,0x38,0x84,0x78,0x20,0x1f,0xff,0xff,0xff,0xf8,0x00, 89 | 0x00,0x18,0x1f,0xff,0xe0,0x03,0x8f,0x0c,0x78,0x00,0x00,0x03,0x8f,0x1e,0x79,0x86, 90 | 0x7e,0xe0,0x1f,0xff,0xff,0xff,0xe0,0x00,0x00,0x18,0x0f,0xff,0xe0,0x03,0xfe,0x1f, 91 | 0xf0,0x00,0x00,0x03,0xfe,0x0f,0xf0,0xcc,0x3f,0xf0,0x1f,0xff,0xff,0xff,0x00,0x00, 92 | 0x00,0x18,0x07,0xff,0xc0,0x00,0xfc,0x07,0xe0,0x00,0x00,0x00,0xfc,0x07,0xe0,0xfc, 93 | 0x0f,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x03,0xff,0x80,0x00,0x00,0x00, 94 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 95 | 0x00,0x18,0x21,0xfe,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 96 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x70,0x30,0x18,0x00,0x00,0x00, 97 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 98 | 0x00,0x18,0xe0,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 99 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x30,0x00,0x00,0x00,0x00, 100 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 101 | 0x00,0x18,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 102 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x30,0x00,0x00,0x00,0x00, 103 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 104 | 0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 105 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00, 106 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 107 | 0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 108 | 0x00,0x00}; 109 | -------------------------------------------------------------------------------- /examples/uc1609_test/uc1609_test.ino: -------------------------------------------------------------------------------- 1 | // 2 | // OneBitDisplay library GFX demo 3 | // 4 | #include 5 | #include "uc1609.h" // demo bitmap 6 | 7 | #define RESET_PIN 9 8 | #define DC_PIN 8 9 | #define CS_PIN 10 10 | #define MOSI_PIN -1 11 | #define SCK_PIN -1 12 | // don't rotate the display 13 | #define FLIP180 0 14 | // don't invert the display 15 | #define INVERT 0 16 | 17 | #ifndef __AVR__ 18 | #define USE_BACKBUFFER 19 | #endif 20 | 21 | #ifdef USE_BACKBUFFER 22 | uint8_t ucBackBuffer[1536]; 23 | #endif 24 | 25 | // The OBDISP structure 26 | // There is no limit to the number of simultaneous displays which can be controlled by OneBitDisplay 27 | OBDISP obd; 28 | 29 | void setup() { 30 | int rc; 31 | Serial.begin(115200); 32 | 33 | //void obdSPIInit(OBDISP *pOBD, int iType, int iDC, int iCS, int iReset, int iMOSI, int iCLK, int iLED, int bFlip, int bInvert, int iBitBang, int32_t iSpeed); 34 | obdSPIInit(&obd, LCD_UC1609, DC_PIN, CS_PIN, RESET_PIN, MOSI_PIN, SCK_PIN, -1, 0, 0, 0, 4000000); 35 | obdFill(&obd, OBD_WHITE, 1); 36 | obdWriteString(&obd, 0,0,0,(char *)"UC1701 192x64 LCD Demo", FONT_8x8, OBD_BLACK, 1); 37 | delay(4000); 38 | rc = obdLoadBMP(&obd, (uint8_t *)uc1609, 0, 0, OBD_BLACK, OBD_WHITE); 39 | if (rc != 0) 40 | Serial.println("Error displaying bitmap"); 41 | delay(4000); 42 | #ifdef USE_BACKBUFFER 43 | obdSetBackBuffer(&obd, ucBackBuffer); 44 | #endif 45 | } /* setup() */ 46 | 47 | #ifdef USE_BACKBUFFER 48 | #define DRAW_ELLIPSES 49 | #define DRAW_RECTS 50 | #define DRAW_TEXT 51 | #endif 52 | 53 | void loop() { 54 | int i, x, y, x2, y2, r1, r2; 55 | uint8_t ucColor; 56 | unsigned long ulTime; 57 | char szTemp[32]; 58 | 59 | #ifdef DRAW_ELLIPSES 60 | obdFill(&obd, OBD_WHITE, 1); 61 | obdWriteString(&obd, 0, 0, 0, (char *)"Ellipses", FONT_8x8, OBD_BLACK, 1); 62 | delay(2000); 63 | obdFill(&obd, OBD_WHITE, 1); 64 | ulTime = micros(); 65 | for (i=0; i<100; i++) 66 | { 67 | x = random(192); 68 | y = random(64); 69 | r1 = random(64); 70 | r2 = random(32); 71 | obdEllipse(&obd, x, y, r1, r2, OBD_BLACK, 0); 72 | obdDumpBuffer(&obd, NULL); 73 | } 74 | ulTime = micros() - ulTime; 75 | obdFill(&obd, OBD_WHITE, 1); 76 | obdWriteString(&obd, 0, 0, 0, (char *)"100 frames drawn", FONT_8x8, OBD_BLACK, 1); 77 | sprintf(szTemp, "in %d ms", (int)(ulTime/1000)); 78 | obdWriteString(&obd, 0, 0, 1, szTemp, FONT_8x8, OBD_BLACK, 1); 79 | sprintf(szTemp, "%d FPS", 100000000 / (ulTime)); 80 | obdWriteString(&obd, 0, 0, 2, szTemp, FONT_8x8, OBD_BLACK, 1); 81 | delay(4000); 82 | obdFill(&obd, OBD_WHITE, 1); 83 | obdWriteString(&obd, 0, 0, 0, (char *)"Filled Ellipses", FONT_8x8, OBD_BLACK, 1); 84 | delay(2000); 85 | obdFill(&obd, OBD_WHITE, 1); 86 | ulTime = micros(); 87 | for (i=0; i<100; i++) 88 | { 89 | x = random(192); 90 | y = random(64); 91 | r1 = random(64); 92 | r2 = random(32); 93 | ucColor = random(2); 94 | obdEllipse(&obd, x, y, r1, r2, ucColor, 1); 95 | obdDumpBuffer(&obd, NULL); 96 | } 97 | ulTime = micros() - ulTime; 98 | obdFill(&obd, 0, 1); 99 | obdWriteString(&obd, 0, 0, 0, (char *)"100 frames drawn", FONT_8x8, OBD_BLACK, 1); 100 | sprintf(szTemp, "in %d ms", (int)(ulTime/1000)); 101 | obdWriteString(&obd, 0, 0, 1, szTemp, FONT_8x8, OBD_BLACK, 1); 102 | sprintf(szTemp, "%d FPS", 100000000 / (ulTime)); 103 | obdWriteString(&obd, 0, 0, 2, szTemp, FONT_8x8, OBD_BLACK, 1); 104 | delay(4000); 105 | 106 | #endif // DRAW_ELLIPSES 107 | 108 | #ifdef DRAW_RECTS 109 | obdFill(&obd, OBD_WHITE, 1); 110 | obdWriteString(&obd, 0, 0, 0, (char *)"Rectangles", FONT_8x8, OBD_BLACK, 1); 111 | delay(2000); 112 | obdFill(&obd, OBD_WHITE, 1); 113 | ulTime = micros(); 114 | for (i=0; i<100; i++) 115 | { 116 | x = random(192); 117 | y = random(64); 118 | x2 = random(192); 119 | y2 = random(64); 120 | obdRectangle(&obd, x, y, x2, y2, OBD_BLACK, 0); 121 | obdDumpBuffer(&obd, NULL); 122 | } 123 | ulTime = micros() - ulTime; 124 | obdFill(&obd, OBD_WHITE, 1); 125 | obdWriteString(&obd, 0, 0, 0, (char *)"100 frames drawn", FONT_8x8, OBD_BLACK, 1); 126 | sprintf(szTemp, "in %d ms", (int)(ulTime/1000)); 127 | obdWriteString(&obd, 0, 0, 1, szTemp, FONT_8x8, OBD_BLACK, 1); 128 | sprintf(szTemp, "%d FPS", 100000000 / (ulTime)); 129 | obdWriteString(&obd, 0, 0, 2, szTemp, FONT_8x8, OBD_BLACK, 1); 130 | delay(4000); 131 | obdFill(&obd, OBD_WHITE, 1); 132 | obdWriteString(&obd, 0, 0, 0, (char *)"Filled Rects", FONT_8x8, OBD_BLACK, 1); 133 | delay(2000); 134 | obdFill(&obd, OBD_WHITE, 1); 135 | ulTime = micros(); 136 | for (i=0; i<100; i++) 137 | { 138 | x = random(192); 139 | y = random(64); 140 | x2 = random(192); 141 | y2 = random(64); 142 | ucColor = random(2); 143 | obdRectangle(&obd, x, y, x2, y2, ucColor, 1); 144 | obdDumpBuffer(&obd, NULL); 145 | } 146 | ulTime = micros() - ulTime; 147 | obdFill(&obd, OBD_WHITE, 1); 148 | obdWriteString(&obd, 0, 0, 0, (char *)"100 frames drawn", FONT_8x8, OBD_BLACK, 1); 149 | sprintf(szTemp, "in %d ms", (int)(ulTime/1000)); 150 | obdWriteString(&obd, 0, 0, 1, szTemp, FONT_8x8, OBD_BLACK, 1); 151 | sprintf(szTemp, "%d FPS", 100000000 / (ulTime)); 152 | obdWriteString(&obd, 0, 0, 2, szTemp, FONT_8x8, OBD_BLACK, 1); 153 | delay(4000); 154 | #endif // DRAW_RECTS 155 | #ifdef DRAW_TEXT 156 | obdFill(&obd,OBD_WHITE,1); 157 | obdWriteString(&obd,0,0,0,(char *)"Small Font", FONT_8x8, OBD_BLACK, 1); 158 | delay(2000); 159 | obdFill(&obd,OBD_WHITE,1); 160 | ulTime = micros(); 161 | for (i=0; i<100; i++) 162 | { 163 | char szTemp[34]; 164 | szTemp[32] = 0; 165 | x = i; 166 | while (x >= 26) 167 | x -= 26; 168 | for (y=0; y<8; y++) 169 | { 170 | for (x2=0; x2<32; x2++) 171 | { 172 | szTemp[x2] = 'A' + x; 173 | x++; 174 | if (x >= 26) x -= 26; 175 | } 176 | obdWriteString(&obd, 0,0,y,szTemp, FONT_6x8, OBD_BLACK, 1); 177 | } // for y 178 | } 179 | ulTime = micros() - ulTime; 180 | obdFill(&obd, OBD_WHITE, 1); 181 | obdWriteString(&obd, 0, 0, 0, (char *)"16800 chars", FONT_8x8, OBD_BLACK, 1); 182 | sprintf(szTemp, "in %d ms", (int)(ulTime/1000)); 183 | obdWriteString(&obd, 0, 0, 1, szTemp, FONT_8x8, OBD_BLACK, 1); 184 | delay(4000); 185 | obdFill(&obd,OBD_WHITE,1); 186 | obdWriteString(&obd,0,0,0,(char *)"Normal Font", FONT_8x8, OBD_BLACK, 1); 187 | delay(2000); 188 | obdFill(&obd,OBD_WHITE,1); 189 | ulTime = micros(); 190 | for (i=0; i<100; i++) 191 | { 192 | char szTemp[34]; 193 | szTemp[24] = 0; 194 | x = i; 195 | while (x >= 26) 196 | x -= 26; 197 | for (y=0; y<8; y++) 198 | { 199 | for (x2=0; x2<24; x2++) 200 | { 201 | szTemp[x2] = 'A' + x; 202 | x++; 203 | if (x >= 26) x -= 26; 204 | } 205 | obdWriteString(&obd, 0,0,y,szTemp, FONT_8x8, OBD_BLACK, 1); 206 | } // for y 207 | } 208 | ulTime = micros() - ulTime; 209 | obdFill(&obd, OBD_WHITE, 1); 210 | obdWriteString(&obd, 0, 0, 0, (char *)"12800 chars", FONT_8x8, OBD_BLACK, 1); 211 | sprintf(szTemp, "in %d ms", (int)(ulTime/1000)); 212 | obdWriteString(&obd, 0, 0, 1, szTemp, FONT_8x8, OBD_BLACK, 1); 213 | delay(4000); 214 | #endif // DRAW_TEXT 215 | } /* loop() */ 216 | -------------------------------------------------------------------------------- /examples/virtual_display/virtual_display.ino: -------------------------------------------------------------------------------- 1 | // 2 | // OneBitDisplay library demo 3 | // 4 | // Demonstrates how to use virtual displays 5 | // these allow you to create a display of any size in memory 6 | // and draw it across multiple physical displays 7 | // 8 | //#include 9 | #include 10 | OBDISP obLeft; 11 | OBDISP obRight; 12 | OBDISP obVirt; 13 | 14 | // define a 256x64 framebuffer 15 | static uint8_t ucBackBuffer[2048]; 16 | 17 | // Toaster animation images 18 | const uint8_t toastermask0[] = { 19 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 20 | 0x00, 0x20, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 21 | 0x00, 0x10, 0x00, 0x00, 0x00, 0x43, 0xF8, 0x00, 22 | 0x00, 0x1F, 0x80, 0x00, 0x00, 0x7C, 0x3F, 0x80, 23 | 0x01, 0xF1, 0xF8, 0xF0, 0x07, 0xC7, 0xC7, 0x00, 24 | 0x0F, 0x1F, 0x08, 0x2B, 0x1E, 0x7C, 0x11, 0x00, 25 | 0x04, 0xF0, 0x20, 0x56, 0x61, 0xE4, 0x22, 0x00, 26 | 0x78, 0x48, 0x40, 0xA8, 0x4E, 0x10, 0x44, 0x00, 27 | 0x53, 0x90, 0x81, 0xF8, 0x5C, 0xA0, 0x90, 0x58, 28 | 0x7C, 0xA1, 0x07, 0x90, 0x74, 0xA1, 0x21, 0x38, 29 | 0x7F, 0xB5, 0x0E, 0x30, 0x77, 0xB0, 0x90, 0x78, 30 | 0x7F, 0xB4, 0x60, 0xF0, 0x77, 0xBB, 0x03, 0xE0, 31 | 0x7F, 0xBC, 0x0F, 0xC0, 0x77, 0xBF, 0xFF, 0x00, 32 | 0x7F, 0xBF, 0xFC, 0x00, 0x3F, 0xBF, 0xF0, 0x00, 33 | 0x1F, 0xBF, 0xC0, 0x00, 0x07, 0xBE, 0x00, 0x00, 34 | 0x01, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 35 | const uint8_t toastermask1[] = { 36 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 37 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 38 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0xF8, 0x00, 39 | 0x00, 0x1F, 0x80, 0x00, 0x00, 0x7C, 0x3F, 0x80, 40 | 0x01, 0xF1, 0xF8, 0x00, 0x07, 0xC7, 0xC1, 0xE0, 41 | 0x0F, 0x1F, 0x06, 0x10, 0x1E, 0x7C, 0x00, 0x00, 42 | 0x04, 0xF0, 0x07, 0xF0, 0x61, 0xE4, 0x18, 0x08, 43 | 0x78, 0x48, 0x20, 0x80, 0x4E, 0x10, 0x40, 0x2B, 44 | 0x53, 0x90, 0x81, 0x00, 0x5C, 0xA0, 0x80, 0x58, 45 | 0x7C, 0xA1, 0x02, 0x00, 0x74, 0xA1, 0x28, 0xB8, 46 | 0x7F, 0xB5, 0x0F, 0xF0, 0x77, 0xB0, 0x90, 0x78, 47 | 0x7F, 0xB4, 0x60, 0xF0, 0x77, 0xBB, 0x03, 0xE0, 48 | 0x7F, 0xBC, 0x0F, 0xC0, 0x77, 0xBF, 0xFF, 0x00, 49 | 0x7F, 0xBF, 0xFC, 0x00, 0x3F, 0xBF, 0xF0, 0x00, 50 | 0x1F, 0xBF, 0xC0, 0x00, 0x07, 0xBE, 0x00, 0x00, 51 | 0x01, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 52 | const uint8_t toastermask2[] = { 53 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 54 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 55 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF8, 0x00, 56 | 0x00, 0x1F, 0x80, 0x00, 0x00, 0x7C, 0x3F, 0x80, 57 | 0x01, 0xF1, 0xF8, 0x00, 0x07, 0xC7, 0xC1, 0xE0, 58 | 0x0F, 0x1F, 0x06, 0x10, 0x1E, 0x7C, 0x00, 0x00, 59 | 0x04, 0xF0, 0x00, 0x00, 0x61, 0xE4, 0x00, 0x08, 60 | 0x78, 0x48, 0x00, 0x10, 0x4E, 0x10, 0x00, 0x18, 61 | 0x53, 0x90, 0x60, 0x70, 0x5C, 0xA0, 0x9F, 0xC8, 62 | 0x7C, 0xA1, 0x04, 0x92, 0x74, 0xA1, 0x09, 0x24, 63 | 0x7F, 0xB5, 0x02, 0x48, 0x77, 0xB0, 0x80, 0x10, 64 | 0x7F, 0xB4, 0x41, 0x00, 0x77, 0xBB, 0x20, 0x40, 65 | 0x7F, 0xBC, 0x10, 0x00, 0x77, 0xBF, 0xF8, 0x00, 66 | 0x7F, 0xBF, 0xFC, 0x00, 0x3F, 0xBF, 0xF0, 0x00, 67 | 0x1F, 0xBF, 0xC0, 0x00, 0x07, 0xBE, 0x00, 0x00, 68 | 0x01, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 69 | const uint8_t toaster0[] = { 70 | 0x00, 0x30, 0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 71 | 0x01, 0xD8, 0x00, 0x00, 0x03, 0x74, 0xF0, 0x00, 72 | 0x07, 0xEF, 0xFE, 0x00, 0x07, 0xBC, 0x07, 0x80, 73 | 0x0F, 0xE0, 0x7F, 0xE0, 0x0F, 0x83, 0xC0, 0x70, 74 | 0x1E, 0x0E, 0x07, 0x08, 0x18, 0x38, 0x38, 0xFF, 75 | 0x30, 0xE0, 0xF7, 0xD4, 0x61, 0x83, 0xEE, 0xFF, 76 | 0x7B, 0x0F, 0xDF, 0xA8, 0x9E, 0x1B, 0xDD, 0xFE, 77 | 0x87, 0xB7, 0xBF, 0x50, 0xB1, 0xEF, 0xBB, 0xF8, 78 | 0xAC, 0x6F, 0x7E, 0x00, 0xA3, 0x5F, 0x6F, 0xA0, 79 | 0x83, 0x5E, 0xF8, 0x68, 0x8B, 0x5E, 0xDE, 0xC0, 80 | 0x80, 0x4A, 0xF1, 0xC8, 0x88, 0x4F, 0x6F, 0x80, 81 | 0x80, 0x4B, 0x9F, 0x08, 0x88, 0x44, 0xFC, 0x10, 82 | 0x80, 0x43, 0xF0, 0x20, 0x88, 0x40, 0x00, 0xC0, 83 | 0x80, 0x40, 0x03, 0x00, 0x40, 0x40, 0x0C, 0x00, 84 | 0x20, 0x40, 0x30, 0x00, 0x18, 0x41, 0xC0, 0x00, 85 | 0x06, 0x4E, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00 }; 86 | const uint8_t toaster1[] = { 87 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 88 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xF0, 0x00, 89 | 0x00, 0xF7, 0xFE, 0x00, 0x01, 0xBC, 0x07, 0x80, 90 | 0x03, 0xE0, 0x7F, 0xE0, 0x07, 0x83, 0xC0, 0x70, 91 | 0x0E, 0x0E, 0x07, 0xF8, 0x18, 0x38, 0x3E, 0x18, 92 | 0x30, 0xE0, 0xF9, 0xE8, 0x61, 0x83, 0xFF, 0xF8, 93 | 0x7B, 0x0F, 0xF8, 0x08, 0x9E, 0x1B, 0xE7, 0xF0, 94 | 0x87, 0xB7, 0xDF, 0x7F, 0xB1, 0xEF, 0xBF, 0xD4, 95 | 0xAC, 0x6F, 0x7E, 0xFF, 0xA3, 0x5F, 0x7F, 0xA6, 96 | 0x83, 0x5E, 0xFD, 0xF8, 0x8B, 0x5E, 0xD7, 0x40, 97 | 0x80, 0x4A, 0xF0, 0x08, 0x88, 0x4F, 0x6F, 0x80, 98 | 0x80, 0x4B, 0x9F, 0x08, 0x88, 0x44, 0xFC, 0x10, 99 | 0x80, 0x43, 0xF0, 0x20, 0x88, 0x40, 0x00, 0xC0, 100 | 0x80, 0x40, 0x03, 0x00, 0x40, 0x40, 0x0C, 0x00, 101 | 0x20, 0x40, 0x30, 0x00, 0x18, 0x41, 0xC0, 0x00, 102 | 0x06, 0x4E, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00 }; 103 | const uint8_t toaster2[] = { 104 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 105 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 106 | 0x00, 0x07, 0xFE, 0x00, 0x00, 0x3C, 0x07, 0x80, 107 | 0x00, 0xE0, 0x7F, 0xE0, 0x03, 0x83, 0xC0, 0x70, 108 | 0x0E, 0x0E, 0x07, 0xF8, 0x18, 0x38, 0x3E, 0x18, 109 | 0x30, 0xE0, 0xF9, 0xE8, 0x61, 0x83, 0xFF, 0xF8, 110 | 0x7B, 0x0F, 0xFF, 0xF8, 0x9E, 0x1B, 0xFF, 0xF0, 111 | 0x87, 0xB7, 0xFF, 0xE8, 0xB1, 0xEF, 0xFF, 0xE0, 112 | 0xAC, 0x6F, 0x9F, 0x88, 0xA3, 0x5F, 0x60, 0x36, 113 | 0x83, 0x5E, 0xFB, 0x6D, 0x8B, 0x5E, 0xF6, 0xDB, 114 | 0x80, 0x4A, 0xFD, 0xB6, 0x88, 0x4F, 0x7F, 0xEE, 115 | 0x80, 0x4B, 0xBE, 0xFC, 0x88, 0x44, 0xDF, 0xBC, 116 | 0x80, 0x43, 0xEF, 0xF8, 0x88, 0x40, 0x07, 0xF0, 117 | 0x80, 0x40, 0x03, 0xE0, 0x40, 0x40, 0x0C, 0xC0, 118 | 0x20, 0x40, 0x30, 0x00, 0x18, 0x41, 0xC0, 0x00, 119 | 0x06, 0x4E, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00 }; 120 | uint8_t * toasters[] = {(uint8_t *)toaster0, (uint8_t *)toaster1, (uint8_t *)toaster2, (uint8_t *)toaster1}; 121 | uint8_t * masks[] = {(uint8_t *)toastermask0, (uint8_t *)toastermask1, (uint8_t *)toastermask2, (uint8_t *)toastermask1}; 122 | 123 | void setup() { 124 | int rc; 125 | //int obdI2CInit(OBDISP *pOBD, int iType, int iAddr, int bFlip, int bInvert, int bWire, int iSDAPin, int iSCLPin, int iResetPin, int32_t iSpeed); 126 | // Create a virtual display (memory only) 127 | obdCreateVirtualDisplay(&obVirt, 256, 64, ucBackBuffer); 128 | // Initialize 2 physical OLED displays 129 | // In this case, they are defined on the W600-PICO using bit banging 130 | // Change the SDA and SCL pin definitions to match your setup 131 | rc = obdI2CInit(&obLeft, OLED_128x64, -1, 0, 0,0,WM_IO_PB_12, WM_IO_PA_00,-1,1200000L); 132 | rc = obdI2CInit(&obRight, OLED_128x64, -1, 0, 0,0,WM_IO_PB_11, WM_IO_PA_00,-1,1200000L); 133 | if (rc != OLED_NOT_FOUND) 134 | { 135 | char *msgs[] = {(char *)"SSD1306 @ 0x3C", (char *)"SSD1306 @ 0x3D",(char *)"SH1106 @ 0x3C",(char *)"SH1106 @ 0x3D"}; 136 | obdFill(&obLeft, OBD_WHITE, 1); 137 | obdWriteString(&obLeft,0,0,0,msgs[rc], FONT_8x8, OBD_BLACK, 1); 138 | delay(2000); 139 | } 140 | } 141 | #define NUM_SPRITES 10 142 | void loop() { 143 | int i, x, y; 144 | char szTemp[32]; 145 | unsigned long ms; 146 | int xpos[NUM_SPRITES], ypos[NUM_SPRITES], index[NUM_SPRITES], velocity[NUM_SPRITES]; 147 | 148 | obdFill(&obLeft, OBD_WHITE, 1); 149 | obdWriteString(&obLeft,0,16,0,(char *)"ss_oled Demo", FONT_8x8, OBD_BLACK, 1); 150 | obdWriteString(&obLeft,0,0,1,(char *)"Written by Larry Bank", FONT_6x8, OBD_WHITE, 1); 151 | obdWriteString(&obLeft,0,0,3,(char *)"**Demo**", FONT_16x32, OBD_BLACK, 1); 152 | delay(2000); 153 | 154 | // Sprites 155 | // generate random starting positions, speed and animation frame index 156 | for (i=0; i>2, ypos[i]>>2, 0); 170 | obdDrawSprite(&obVirt,toasters[index[i] & 3], 32, 32, 4, xpos[i]>>2, ypos[i]>>2, 1); 171 | xpos[i]-= velocity[i]; 172 | ypos[i]+= velocity[i]; 173 | index[i]++; 174 | x = xpos[i] >> 2; y = ypos[i] >> 2; 175 | if (x < -31 || y >= 64) 176 | { 177 | xpos[i] = 4*((rand()&255) + 31); 178 | ypos[i] = 4*((rand()&63) - 31); 179 | } 180 | } 181 | // Show the left half of the virtual display on the left OLED 182 | obdDumpWindow(&obVirt, &obLeft,0,0,0,0,128,64); 183 | // and the right half on the right OLED 184 | obdDumpWindow(&obVirt, &obRight,128,0,0,0,128,64); 185 | } // while (1) 186 | } /* main() */ 187 | -------------------------------------------------------------------------------- /fontconvert/Makefile: -------------------------------------------------------------------------------- 1 | all: fontconvert 2 | 3 | CC = gcc 4 | CFLAGS = -Wall -I/usr/local/include/freetype2 -I/usr/include/freetype2 -I/usr/include -I/opt/homebrew/include/freetype2 5 | LIBS = -L/opt/homebrew/lib -lfreetype 6 | 7 | fontconvert: main.c 8 | $(CC) $(CFLAGS) main.c $(LIBS) -o fontconvert 9 | strip fontconvert 10 | 11 | clean: 12 | rm -f fontconvert 13 | -------------------------------------------------------------------------------- /fontconvert/README.txt: -------------------------------------------------------------------------------- 1 | TrueType font convert tool 2 | -------------------------- 3 | This program was written by Adafruit and I modified it to map characters 4 | 128 to 255 from Unicode to the Microsoft codepage 1252 set. This allows 5 | you to support nearly all European/Western languages with direct use 6 | of UTF-8 Unicode strings from your projects. It's not a perfect solution, 7 | but it's better than not being able to use those symbols and accented 8 | characters. See the Unicode_demo for an example of how to use them. 9 | 10 | Build the tool with GCC and Make. I've tested this on MacOS and Linux, 11 | but it should work on Windows too. 12 | 13 | -------------------------------------------------------------------------------- /fontconvert/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | TrueType to Adafruit_GFX font converter. Derived from Peter Jakobs' 3 | Adafruit_ftGFX fork & makefont tool, and Paul Kourany's Adafruit_mfGFX. 4 | 5 | NOT AN ARDUINO SKETCH. This is a command-line tool for preprocessing 6 | fonts to be used with the Adafruit_GFX Arduino library. 7 | 8 | For UNIX-like systems. Outputs to stdout; redirect to header file, e.g.: 9 | ./fontconvert ~/Library/Fonts/FreeSans.ttf 18 > FreeSans18pt7b.h 10 | 11 | REQUIRES FREETYPE LIBRARY. www.freetype.org 12 | 13 | Currently this only extracts the printable 7-bit ASCII chars of a font. 14 | Will eventually extend with some int'l chars a la ftGFX, not there yet. 15 | Keep 7-bit fonts around as an option in that case, more compact. 16 | 17 | See notes at end for glyph nomenclature & other tidbits. 18 | */ 19 | #ifndef ARDUINO 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include FT_GLYPH_H 26 | #include FT_MODULE_H 27 | #include FT_TRUETYPE_DRIVER_H 28 | 29 | typedef struct { 30 | uint16_t bitmapOffset; ///< Pointer into GFXfont->bitmap 31 | uint16_t width; ///< Bitmap dimensions in pixels 32 | uint16_t height; ///< Bitmap dimensions in pixels 33 | uint16_t xAdvance; ///< Distance to advance cursor (x axis) 34 | int16_t xOffset; ///< X dist from cursor pos to UL corner 35 | int16_t yOffset; ///< Y dist from cursor pos to UL corner 36 | } GFXglyph; 37 | 38 | /// Data stored for FONT AS A WHOLE 39 | typedef struct { 40 | uint8_t *bitmap; ///< Glyph bitmaps, concatenated 41 | GFXglyph *glyph; ///< Glyph array 42 | uint8_t first; ///< ASCII extents (first char) 43 | uint8_t last; ///< ASCII extents (last char) 44 | int16_t yAdvance; ///< Newline distance (y axis) 45 | } GFXfont; 46 | 47 | #define DPI 141 // Approximate res. of Adafruit 2.8" TFT 48 | 49 | // Accumulate bits for output, with periodic hexadecimal byte write 50 | void enbit(uint8_t value) { 51 | static uint8_t row = 0, sum = 0, bit = 0x80, firstCall = 1; 52 | if (value) 53 | sum |= bit; // Set bit if needed 54 | if (!(bit >>= 1)) { // Advance to next bit, end of byte reached? 55 | if (!firstCall) { // Format output table nicely 56 | if (++row >= 12) { // Last entry on line? 57 | printf(",\n "); // Newline format output 58 | row = 0; // Reset row counter 59 | } else { // Not end of line 60 | printf(", "); // Simple comma delim 61 | } 62 | } 63 | printf("0x%02X", sum); // Write byte value 64 | sum = 0; // Clear for next byte 65 | bit = 0x80; // Reset bit counter 66 | firstCall = 0; // Formatting flag 67 | } 68 | } 69 | // 70 | // Lookup table to convert codepage 1252 to Unicode 71 | // 72 | const uint16_t uc1252Table[256] = { 73 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0-15 not used (some can be mapped to printable characters if needed) 74 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 16-31 not used 75 | 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, 76 | 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, 77 | 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, 78 | 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, 79 | 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, 80 | 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, 81 | // Now starts the remapped Unicode characters 82 | 0x20ac, 32, 0x201a, 0x192, 0x201e, 0x2026, 0x2020, 0x2021, 0x2c6, 0x2030,0x160,0x2039,0x152,32,0x17d,32, // 0x80-0x8f 83 | 32, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x2dc, 0x2122, 0x161, 0x2031, 0x153, 32, 0x17e, 0x178, // 0x90-0x9f 84 | 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf, 85 | 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf, 86 | 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf, 87 | 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf, 88 | 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef, 89 | 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff 90 | }; 91 | 92 | int main(int argc, char *argv[]) { 93 | int i, j, err, size, first = ' ', last = '~', bitmapOffset = 0, x, y, byte; 94 | char *fontName, c, *ptr; 95 | FT_Library library; 96 | FT_Face face; 97 | FT_Glyph glyph; 98 | FT_Bitmap *bitmap; 99 | FT_BitmapGlyphRec *g; 100 | GFXglyph *table; 101 | uint8_t bit; 102 | 103 | // Parse command line. Valid syntaxes are: 104 | // fontconvert [filename] [size] 105 | // fontconvert [filename] [size] [last char] 106 | // fontconvert [filename] [size] [first char] [last char] 107 | // Unless overridden, default first and last chars are 108 | // ' ' (space) and '~', respectively 109 | 110 | if (argc < 3) { 111 | fprintf(stderr, "Usage: %s fontfile size [first] [last]\n", argv[0]); 112 | return 1; 113 | } 114 | 115 | size = atoi(argv[2]); 116 | 117 | if (argc == 4) { 118 | last = atoi(argv[3]); 119 | } else if (argc == 5) { 120 | first = atoi(argv[3]); 121 | last = atoi(argv[4]); 122 | } 123 | 124 | if (last < first) { 125 | i = first; 126 | first = last; 127 | last = i; 128 | } 129 | 130 | ptr = strrchr(argv[1], '/'); // Find last slash in filename 131 | if (ptr) 132 | ptr++; // First character of filename (path stripped) 133 | else 134 | ptr = argv[1]; // No path; font in local dir. 135 | 136 | // Allocate space for font name and glyph table 137 | if ((!(fontName = malloc(strlen(ptr) + 20))) || 138 | (!(table = (GFXglyph *)malloc((last - first + 1) * sizeof(GFXglyph))))) { 139 | fprintf(stderr, "Malloc error\n"); 140 | return 1; 141 | } 142 | 143 | // Derive font table names from filename. Period (filename 144 | // extension) is truncated and replaced with the font size & bits. 145 | strcpy(fontName, ptr); 146 | ptr = strrchr(fontName, '.'); // Find last period (file ext) 147 | if (!ptr) 148 | ptr = &fontName[strlen(fontName)]; // If none, append 149 | // Insert font size and 7/8 bit. fontName was alloc'd w/extra 150 | // space to allow this, we're not sprintfing into Forbidden Zone. 151 | sprintf(ptr, "%dpt%db", size, (last > 127) ? 8 : 7); 152 | // Space and punctuation chars in name replaced w/ underscores. 153 | for (i = 0; (c = fontName[i]); i++) { 154 | if (isspace(c) || ispunct(c)) 155 | fontName[i] = '_'; 156 | } 157 | 158 | // Init FreeType lib, load font 159 | if ((err = FT_Init_FreeType(&library))) { 160 | fprintf(stderr, "FreeType init error: %d", err); 161 | return err; 162 | } 163 | 164 | // Use TrueType engine version 35, without subpixel rendering. 165 | // This improves clarity of fonts since this library does not 166 | // support rendering multiple levels of gray in a glyph. 167 | // See https://github.com/adafruit/Adafruit-GFX-Library/issues/103 168 | FT_UInt interpreter_version = TT_INTERPRETER_VERSION_35; 169 | FT_Property_Set(library, "truetype", "interpreter-version", 170 | &interpreter_version); 171 | 172 | if ((err = FT_New_Face(library, argv[1], 0, &face))) { 173 | fprintf(stderr, "Font load error: %d", err); 174 | FT_Done_FreeType(library); 175 | return err; 176 | } 177 | 178 | // << 6 because '26dot6' fixed-point format 179 | FT_Set_Char_Size(face, size << 6, 0, DPI, 0); 180 | 181 | // Currently all symbols from 'first' to 'last' are processed. 182 | // Fonts may contain WAY more glyphs than that, but this code 183 | // will need to handle encoding stuff to deal with extracting 184 | // the right symbols, and that's not done yet. 185 | // fprintf(stderr, "%ld glyphs\n", face->num_glyphs); 186 | 187 | printf("const uint8_t %sBitmaps[] PROGMEM = {\n ", fontName); 188 | 189 | // Process glyphs and output huge bitmap data array 190 | for (i = first, j = 0; i <= last; i++, j++) { 191 | int iChar = uc1252Table[i]; // convert CP1252 to Unicode 192 | // MONO renderer provides clean image with perfect crop 193 | // (no wasted pixels) via bitmap struct. 194 | if ((err = FT_Load_Char(face, iChar, FT_LOAD_TARGET_MONO))) { 195 | fprintf(stderr, "Error %d loading char '%c'\n", err, iChar); 196 | continue; 197 | } 198 | 199 | if ((err = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO))) { 200 | fprintf(stderr, "Error %d rendering char '%c'\n", err, iChar); 201 | continue; 202 | } 203 | 204 | if ((err = FT_Get_Glyph(face->glyph, &glyph))) { 205 | fprintf(stderr, "Error %d getting glyph '%c'\n", err, iChar); 206 | continue; 207 | } 208 | 209 | bitmap = &face->glyph->bitmap; 210 | g = (FT_BitmapGlyphRec *)glyph; 211 | 212 | // Minimal font and per-glyph information is stored to 213 | // reduce flash space requirements. Glyph bitmaps are 214 | // fully bit-packed; no per-scanline pad, though end of 215 | // each character may be padded to next byte boundary 216 | // when needed. 16-bit offset means 64K max for bitmaps, 217 | // code currently doesn't check for overflow. (Doesn't 218 | // check that size & offsets are within bounds either for 219 | // that matter...please convert fonts responsibly.) 220 | table[j].bitmapOffset = bitmapOffset; 221 | table[j].width = bitmap->width; 222 | table[j].height = bitmap->rows; 223 | table[j].xAdvance = face->glyph->advance.x >> 6; 224 | table[j].xOffset = g->left; 225 | table[j].yOffset = 1 - g->top; 226 | 227 | for (y = 0; y < bitmap->rows; y++) { 228 | for (x = 0; x < bitmap->width; x++) { 229 | byte = x / 8; 230 | bit = 0x80 >> (x & 7); 231 | enbit(bitmap->buffer[y * bitmap->pitch + byte] & bit); 232 | } 233 | } 234 | 235 | // Pad end of char bitmap to next byte boundary if needed 236 | int n = (bitmap->width * bitmap->rows) & 7; 237 | if (n) { // Pixel count not an even multiple of 8? 238 | n = 8 - n; // # bits to next multiple 239 | while (n--) 240 | enbit(0); 241 | } 242 | bitmapOffset += (bitmap->width * bitmap->rows + 7) / 8; 243 | 244 | FT_Done_Glyph(glyph); 245 | } 246 | 247 | printf(" };\n\n"); // End bitmap array 248 | 249 | // Output glyph attributes table (one per character) 250 | printf("const GFXglyph %sGlyphs[] PROGMEM = {\n", fontName); 251 | for (i = first, j = 0; i <= last; i++, j++) { 252 | printf(" { %5d, %3d, %3d, %3d, %4d, %4d }", table[j].bitmapOffset, 253 | table[j].width, table[j].height, table[j].xAdvance, table[j].xOffset, 254 | table[j].yOffset); 255 | if (i < last) { 256 | printf(", // 0x%02X", i); 257 | if ((i >= ' ') && (i <= '~')) { 258 | printf(" '%c'", i); 259 | } 260 | putchar('\n'); 261 | } 262 | } 263 | printf(" }; // 0x%02X", last); 264 | if ((last >= ' ') && (last <= '~')) 265 | printf(" '%c'", last); 266 | printf("\n\n"); 267 | 268 | // Output font structure 269 | printf("const GFXfont %s PROGMEM = {\n", fontName); 270 | printf(" (uint8_t *)%sBitmaps,\n", fontName); 271 | printf(" (GFXglyph *)%sGlyphs,\n", fontName); 272 | if (face->size->metrics.height == 0) { 273 | // No face height info, assume fixed width and get from a glyph. 274 | printf(" 0x%02X, 0x%02X, %d };\n\n", first, last, table[0].height); 275 | } else { 276 | printf(" 0x%02X, 0x%02X, %ld };\n\n", first, last, 277 | face->size->metrics.height >> 6); 278 | } 279 | printf("// Approx. %d bytes\n", bitmapOffset + (last - first + 1) * 7 + 7); 280 | // Size estimate is based on AVR struct and pointer sizes; 281 | // actual size may vary. 282 | 283 | FT_Done_FreeType(library); 284 | 285 | return 0; 286 | } 287 | 288 | /* ------------------------------------------------------------------------- 289 | 290 | Character metrics are slightly different from classic GFX & ftGFX. 291 | In classic GFX: cursor position is the upper-left pixel of each 5x7 292 | character; lower extent of most glyphs (except those w/descenders) 293 | is +6 pixels in Y direction. 294 | W/new GFX fonts: cursor position is on baseline, where baseline is 295 | 'inclusive' (containing the bottom-most row of pixels in most symbols, 296 | except those with descenders; ftGFX is one pixel lower). 297 | 298 | Cursor Y will be moved automatically when switching between classic 299 | and new fonts. If you switch fonts, any print() calls will continue 300 | along the same baseline. 301 | 302 | ...........#####.. -- yOffset 303 | ..........######.. 304 | ..........######.. 305 | .........#######.. 306 | ........#########. 307 | * = Cursor pos. ........#########. 308 | .......##########. 309 | ......#####..####. 310 | ......#####..####. 311 | *.#.. .....#####...####. 312 | .#.#. ....############## 313 | #...# ...############### 314 | #...# ...############### 315 | ##### ..#####......##### 316 | #...# .#####.......##### 317 | ====== #...# ====== #*###.........#### ======= Baseline 318 | || xOffset 319 | 320 | glyph->xOffset and yOffset are pixel offsets, in GFX coordinate space 321 | (+Y is down), from the cursor position to the top-left pixel of the 322 | glyph bitmap. i.e. yOffset is typically negative, xOffset is typically 323 | zero but a few glyphs will have other values (even negative xOffsets 324 | sometimes, totally normal). glyph->xAdvance is the distance to move 325 | the cursor on the X axis after drawing the corresponding symbol. 326 | 327 | There's also some changes with regard to 'background' color and new GFX 328 | fonts (classic fonts unchanged). See Adafruit_GFX.cpp for explanation. 329 | */ 330 | 331 | #endif /* !ARDUINO */ 332 | -------------------------------------------------------------------------------- /fonts_opt.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitbank2/OneBitDisplay/5c5e1b9c2ebd08a63e66c39460514a9d811bb921/fonts_opt.jpg -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=OneBitDisplay 2 | version=2.3.3 3 | author=Larry Bank 4 | maintainer=Larry Bank 5 | sentence=OLED, LCD and e-paper library for 1-bit per pixel displays. 6 | paragraph=Supports most monochrome OLEDs, LCDs, Sharp Memory LCDs and many e-paper displays. Designed to provide a rich set of features with a simple API. Can automatically detect the display address (3C or 3D) and the controller type (SSD1306, SH1106 or SH1107). Includes 5 sizes of fixed fonts (6x8, 8x8, 12x16, 16x16, 16x32). Can use I2C, SPI or bit bang I2C+SPI on any GPIO pins with the use of my BitBang_I2C library. Supports display sizes of: 128x128, 128x64, 128x32, 64x32, 96x16, 72x40. Includes scrolling text/gfx, deferred rendering, lines, sprites, circles, rectangles and more. 7 | category=Display 8 | url=https://github.com/bitbank2/OneBitDisplay 9 | architectures=* 10 | includes=OneBitDisplay.h 11 | depends=BitBang_I2C 12 | -------------------------------------------------------------------------------- /linux/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-c -Wall -O2 -I../src -DSPI_BUS_NUMBER=0 2 | LIBS = -lm -lpthread 3 | 4 | all: libOneBitDisplay.a 5 | 6 | libOneBitDisplay.a: obd.o ../src/OneBitDisplay.h 7 | ar -rc libOneBitDisplay.a obd.o ;\ 8 | sudo cp libOneBitDisplay.a /usr/local/lib ;\ 9 | sudo cp ../src/OneBitDisplay.h /usr/local/include 10 | 11 | obd.o: obd.c ../src/obd.inl ../src/OneBitDisplay.h 12 | $(CC) $(CFLAGS) -D_LINUX_ obd.c 13 | 14 | clean: 15 | rm *.o libOneBitDisplay.a 16 | -------------------------------------------------------------------------------- /linux/OLED_demo/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-c -Wall -O3 -D_LINUX_ -DSPI_BUS_NUMBER=0 2 | LFLAGS= -larmbianio -pthread 3 | all: oled_demo 4 | 5 | oled_demo: main.o 6 | $(CC) -lpthread main.o $(LFLAGS) -o oled_demo 7 | 8 | main.o: main.c ../../src/obd.inl ../../src/OneBitDisplay.cpp ../../src/OneBitDisplay.h 9 | $(CC) $(CFLAGS) main.c 10 | 11 | clean: 12 | rm -rf *.o oled_demo 13 | -------------------------------------------------------------------------------- /linux/OLED_demo/main.c: -------------------------------------------------------------------------------- 1 | // 2 | // main.c 3 | // OneBitDisplay library test program 4 | // Demonstrates many of the features for OLED displays 5 | // 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "../../src/OneBitDisplay.cpp" 19 | 20 | volatile int iStop = 0; 21 | 22 | #define OLED_TYPE OLED_128x64 23 | #define OLED_ADDR 0x3c 24 | #define FLIP180 0 25 | #define INVERT 0 26 | #define HW_I2C 1 27 | // On Linux this is the I2C bus number (SDA_PIN) for HW I2C 28 | #define SDA_PIN 1 29 | // On Linux this is the I2C device address 30 | #define SCL_PIN 0x3c 31 | #define RESET_PIN -1 32 | // This is not controlled on Linux through the API 33 | // On the Raspberry PI, see /boot/config.txt 34 | #define SPEED 0 35 | #define MAX_THREADS 2 36 | void *OLEDThread(void *); 37 | 38 | OBDISP obd[MAX_THREADS]; 39 | 40 | void my_handler(int signal) 41 | { 42 | iStop = 1; 43 | } /* my_handler() */ 44 | 45 | int main(int argc, const char *argv[]) 46 | { 47 | int i, ID[MAX_THREADS]; 48 | pthread_t tinfo[MAX_THREADS]; 49 | struct sigaction sigIntHandler; 50 | size_t ret; 51 | 52 | // Set CTRL-C signal handler 53 | sigIntHandler.sa_handler = my_handler; 54 | sigemptyset(&sigIntHandler.sa_mask); 55 | sigIntHandler.sa_flags = 0; 56 | sigaction(SIGINT, &sigIntHandler, NULL); 57 | 58 | for (i=0; i 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "../../src/OneBitDisplay.cpp" 18 | 19 | volatile int iStop = 0; 20 | 21 | #define DISPLAY_TYPE SHARP_400x240 22 | #define FLIP180 0 23 | #define INVERT 0 24 | #define DC_PIN -1 25 | #define CS_PIN 16 26 | #define DISP_PIN 18 27 | #define EXTCOM_PIN 22 28 | #define RESET_PIN -1 29 | #define SPEED 4000000 30 | #define BITBANG 0 31 | #define LED_PIN -1 32 | OBDISP obd; 33 | static uint8_t ucBuffer[12000]; 34 | 35 | void my_handler(int signal) 36 | { 37 | iStop = 1; 38 | } /* my_handler() */ 39 | 40 | int main(int argc, const char *argv[]) 41 | { 42 | int i; 43 | struct sigaction sigIntHandler; 44 | //size_t ret; 45 | 46 | // Set CTRL-C signal handler 47 | sigIntHandler.sa_handler = my_handler; 48 | sigemptyset(&sigIntHandler.sa_mask); 49 | sigIntHandler.sa_flags = 0; 50 | sigaction(SIGINT, &sigIntHandler, NULL); 51 | 52 | printf("Sharp Memory LCD demo\n"); 53 | printf("Press Ctrl-C to quit\n"); 54 | 55 | i = AIOInitBoard("Raspberry Pi"); 56 | if (i == 0) // problem 57 | { 58 | printf("Error in AIOInit(); check if this board is supported\n"); 59 | return 0; 60 | } 61 | AIOAddGPIO(DISP_PIN, OUTPUT); // enable display 62 | AIOWriteGPIO(DISP_PIN, HIGH); 63 | AIOAddGPIO(EXTCOM_PIN, OUTPUT); 64 | 65 | //void obdSPIInit(OBDISP *pOBD, int iType, int iDC, int iCS, int iReset, int iMOSI, int iCLK, int iLED, int bFlip, int bInvert, int bBitBang, int32_t iSpeed) 66 | obdSPIInit(&obd, DISPLAY_TYPE, DC_PIN, CS_PIN, RESET_PIN, -1, -1, LED_PIN, FLIP180, INVERT, BITBANG, SPEED); 67 | obdSetBackBuffer(&obd, ucBuffer); 68 | //obdSetRotation(&obd, 270); 69 | // Create some simple content 70 | obdFill(&obd, 0, 0); 71 | obdWriteString(&obd,0,0,0,"OneBitDisplay", FONT_16x32, OBD_BLACK, 0); 72 | for (int i=0; i<400; i+=3) { 73 | obdDrawLine(&obd, i, 0, 399-i, 239, OBD_BLACK, 0); 74 | obdDumpBuffer(&obd, NULL); 75 | } 76 | // for (int i=0; i<240; i+=3) { 77 | // obdDrawLine(&obd, 399, i, 0, 239-i, OBD_BLACK, 0); 78 | // } 79 | obdDumpBuffer(&obd, NULL); 80 | while (!iStop) { // toggle the EXTCOM signal until the user hits CTRL-C 81 | AIOWriteGPIO(EXTCOM_PIN, LOW); 82 | usleep(500000); // toggle ext com at 1hz 83 | AIOWriteGPIO(EXTCOM_PIN, HIGH); 84 | usleep(500000); 85 | } 86 | AIOWriteGPIO(DISP_PIN, LOW); // turn off LCD 87 | AIOShutdown(); 88 | return 0; 89 | } /* main() */ 90 | -------------------------------------------------------------------------------- /linux/epd_cpp_demo/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-c -Wall -O2 -DSPI_BUS_NUMBER=0 -D_LINUX_ 2 | LIBS = -lpthread -larmbianio 3 | all: epd_demo 4 | 5 | epd_demo: main.o OneBitDisplay.o 6 | g++ main.o OneBitDisplay.o $(LIBS) -o epd_demo 7 | 8 | main.o: main.cpp ../../src/obd.inl ../../src/OneBitDisplay.cpp ../../src/OneBitDisplay.h 9 | g++ $(CFLAGS) main.cpp 10 | 11 | OneBitDisplay.o: ../../src/OneBitDisplay.cpp ../../src/OneBitDisplay.h ../../src/obd.inl 12 | g++ $(CFLAGS) ../../src/OneBitDisplay.cpp 13 | 14 | clean: 15 | rm -rf *.o epd_demo 16 | -------------------------------------------------------------------------------- /linux/epd_cpp_demo/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Inky Phat (old) test 3 | // 104x212 e-paper (SSD1608) 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "../../src/OneBitDisplay.h" 10 | //#include "Roboto_Black_40.h" 11 | //#include "Roboto_Black_20.h" 12 | 13 | ONE_BIT_DISPLAY epd; 14 | 15 | #define EPD_FREQ 2000000 16 | // Waveshare 2.13 250x122 hat 17 | #define INKY_CS 24 18 | #define INKY_BUSY 18 19 | #define INKY_DC 22 20 | #define INKY_RES 11 21 | 22 | //#define INKY_CS 27 23 | //#define INKY_BUSY 11 24 | //#define INKY_DC 15 25 | //#define INKY_RES 13 26 | #define INKY_MOSI -1 27 | #define INKY_SCK -1 28 | 29 | int main(int argc, char **argv) 30 | { 31 | AIOInitBoard("Raspberry Pi"); 32 | printf("Starting...\n"); 33 | epd.setSPIPins(INKY_CS, -1, -1, INKY_DC, INKY_RES, INKY_BUSY); 34 | epd.SPIbegin(EPD213_104x212, EPD_FREQ); 35 | epd.setRotation(270); 36 | epd.allocBuffer(); 37 | epd.fillScreen(0); 38 | 39 | epd.setFont(FONT_12x16); 40 | epd.println("Inky Phat with"); 41 | epd.println("OneBitDisplay lib"); 42 | epd.setTextColor(OBD_RED); 43 | epd.println(1234, DEC); 44 | epd.println(4095, HEX); 45 | epd.display(); 46 | printf("Display done\n"); 47 | return 0; 48 | } /* main() */ 49 | -------------------------------------------------------------------------------- /linux/epd_demo/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-c -Wall -O2 -DSPI_BUS_NUMBER=0 -D_LINUX_ 2 | LIBS = -larmbianio -lOneBitDisplay -pthread 3 | all: epd_demo 4 | 5 | epd_demo: main.o 6 | $(CC) main.o $(LIBS) -o epd_demo 7 | 8 | main.o: main.c 9 | $(CC) $(CFLAGS) main.c 10 | 11 | clean: 12 | rm -rf *.o epd_demo 13 | -------------------------------------------------------------------------------- /linux/epd_demo/Roboto_Black_28.h: -------------------------------------------------------------------------------- 1 | // Created by http://oleddisplay.squix.ch/ Consider a donation 2 | // In case of problems make sure that you are using the font file with the correct version! 3 | const uint8_t Roboto_Black_28Bitmaps[] PROGMEM = { 4 | 5 | // Bitmap Data: 6 | 0x00, // ' ' 7 | 0xFB,0xEF,0x3C,0xF3,0xCF,0x3C,0xF3,0xCF,0x3C,0xF0,0x00,0x3C,0xF3,0xEF,0x3C, // '!' 8 | 0xF7,0x7B,0xB9,0xDC,0xEE,0x77,0x3B,0x9D,0xCE, // '"' 9 | 0x03,0x18,0x03,0x9C,0x01,0xCE,0x00,0xE7,0x00,0x73,0x80,0x39,0x81,0xFF,0xFC,0xFF,0xFE,0x7F,0xFF,0x07,0x38,0x03,0x9C,0x01,0xCC,0x0F,0xFF,0xE7,0xFF,0xF3,0xFF,0xF8,0x39,0xC0,0x1C,0xE0,0x0E,0x70,0x06,0x30,0x07,0x38,0x00, // '#' 10 | 0x03,0x80,0x07,0x00,0x0E,0x00,0x7E,0x01,0xFF,0x07,0xFF,0x1F,0xFE,0x3E,0x3E,0x78,0x7C,0xF8,0x01,0xF8,0x01,0xFC,0x01,0xFE,0x01,0xFE,0x00,0xFE,0x00,0x7E,0xF8,0x7D,0xF0,0xFB,0xF1,0xF3,0xFF,0xE7,0xFF,0x87,0xFE,0x03,0xF8,0x01,0x80,0x03,0x00,0x06,0x00, // '$' 11 | 0x3E,0x00,0x07,0xF0,0x00,0xFF,0x84,0x0E,0x38,0xE0,0xE3,0x8C,0x0E,0x39,0xC0,0xFF,0xB8,0x07,0xF3,0x80,0x3E,0x70,0x00,0x06,0x00,0x00,0xE0,0x00,0x1C,0xF0,0x01,0xFF,0xC0,0x3B,0xFC,0x07,0x39,0xE0,0x73,0x8E,0x0E,0x39,0xE0,0xE3,0xFC,0x14,0x3F,0xC0,0x00,0xF0, // '%' 12 | 0x07,0xC0,0x07,0xF8,0x03,0xFF,0x00,0xFF,0xC0,0x3C,0xF0,0x0F,0x1C,0x03,0xCF,0x00,0xFF,0x80,0x1F,0xC0,0x07,0xE0,0x03,0xF8,0xF1,0xFF,0x3C,0xFB,0xEF,0x3C,0x7F,0xCF,0x0F,0xE3,0xE1,0xF8,0xFF,0xFC,0x1F,0xFF,0x83,0xFF,0xF0,0x7E,0x3E, // '&' 13 | 0xF7,0xBD,0xEE,0x73,0x9C, // ''' 14 | 0x02,0x0E,0x1E,0x1C,0x38,0x78,0x78,0x70,0xF0,0xF0,0xF0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xF0,0xF0,0xF0,0x70,0x70,0x78,0x38,0x3C,0x1E,0x0E,0x02, // '(' 15 | 0x80,0x70,0x3C,0x0F,0x03,0x81,0xE0,0x70,0x3C,0x1E,0x0F,0x07,0x81,0xC0,0xF0,0x78,0x3C,0x1E,0x0F,0x0F,0x07,0x83,0xC1,0xE1,0xE0,0xF0,0x70,0x78,0x78,0x38,0x10,0x00, // ')' 16 | 0x07,0x00,0x1C,0x00,0x70,0x18,0xC4,0x7B,0xFB,0xFF,0xC0,0x70,0x03,0xE0,0x1D,0xC0,0xE3,0x83,0x8E,0x04,0x20, // '*' 17 | 0x0F,0x80,0x3E,0x00,0xF8,0x03,0xE0,0x0F,0x83,0xFF,0xEF,0xFF,0xBF,0xFE,0xFF,0xF8,0x3E,0x00,0xF8,0x03,0xE0,0x0F,0x80,0x3E,0x00, // '+' 18 | 0x79,0xE7,0x9E,0x79,0xE7,0x38,0x60, // ',' 19 | 0xFF,0x7F,0xBF,0xDF,0xE0, // '-' 20 | 0x73,0xCF,0xBE,0x70, // '.' 21 | 0x03,0xC0,0x70,0x0E,0x03,0xC0,0x70,0x0E,0x03,0xC0,0x70,0x0E,0x03,0xC0,0x70,0x0E,0x01,0xC0,0x78,0x0E,0x01,0xC0,0x78,0x0E,0x01,0xC0,0x78,0x0E,0x01,0xC0,0x00, // '/' 22 | 0x0F,0xC0,0x3F,0xC0,0xFF,0xC3,0xFF,0xC7,0xCF,0x9F,0x0F,0xBE,0x1F,0x7C,0x3E,0xF8,0x7D,0xF0,0xFB,0xE1,0xF7,0xC3,0xEF,0x87,0xDF,0x0F,0xBE,0x1F,0x3E,0x7C,0x7F,0xF8,0x7F,0xE0,0xFF,0xC0,0x7E,0x00, // '0' 23 | 0x00,0x81,0xE3,0xFB,0xFE,0xFF,0xBF,0xEC,0x78,0x1E,0x07,0x81,0xE0,0x78,0x1E,0x07,0x81,0xE0,0x78,0x1E,0x07,0x81,0xE0,0x78,0x1E, // '1' 24 | 0x0F,0xC0,0x7F,0xE1,0xFF,0xE7,0xFF,0xCF,0x8F,0x9F,0x0F,0x3C,0x1F,0x00,0x3C,0x00,0xF8,0x03,0xE0,0x0F,0x80,0x3F,0x00,0xFC,0x03,0xF0,0x0F,0xC0,0x3F,0x00,0xFF,0xFD,0xFF,0xFB,0xFF,0xF7,0xFF,0xE0, // '2' 25 | 0x0F,0xC0,0x7F,0xE1,0xFF,0xE7,0xFF,0xCF,0x8F,0xDE,0x0F,0x80,0x1F,0x00,0x7C,0x0F,0xF8,0x1F,0xC0,0x3F,0xC0,0x7F,0xC0,0x07,0xC0,0x0F,0xBC,0x1F,0x7C,0x3E,0xFF,0xFC,0xFF,0xF0,0xFF,0xC0,0x7E,0x00, // '3' 26 | 0x01,0xF0,0x03,0xE0,0x0F,0xC0,0x3F,0x80,0x7F,0x01,0xFE,0x03,0xBC,0x0F,0x78,0x3C,0xF0,0x79,0xE1,0xE3,0xC7,0x87,0x8F,0xFF,0xDF,0xFF,0xBF,0xFF,0x7F,0xFE,0x00,0xF0,0x01,0xE0,0x03,0xC0,0x07,0x80, // '4' 27 | 0x3F,0xF8,0xFF,0xF1,0xFF,0xE3,0xFF,0xC7,0x80,0x0F,0x00,0x1E,0x00,0x3D,0xF0,0x7F,0xF0,0xFF,0xF3,0xFF,0xE0,0x87,0xE0,0x07,0xC0,0x0F,0xBE,0x1F,0x7C,0x7E,0xFF,0xF8,0xFF,0xF0,0xFF,0xC0,0x7E,0x00, // '5' 28 | 0x01,0xE0,0x0F,0xC0,0x7F,0x81,0xFF,0x03,0xF0,0x0F,0x80,0x1F,0x00,0x7D,0xF0,0xFF,0xF1,0xFF,0xF3,0xFF,0xF7,0xC3,0xEF,0x83,0xDF,0x07,0xBE,0x0F,0x3E,0x3E,0x7F,0xFC,0x7F,0xF0,0x7F,0xC0,0x3E,0x00, // '6' 29 | 0xFF,0xFD,0xFF,0xFB,0xFF,0xF7,0xFF,0xE0,0x07,0x80,0x1F,0x00,0x3C,0x00,0x78,0x01,0xF0,0x03,0xC0,0x0F,0x80,0x1E,0x00,0x7C,0x00,0xF0,0x03,0xE0,0x07,0xC0,0x1F,0x00,0x3E,0x00,0xF8,0x01,0xF0,0x00, // '7' 30 | 0x0F,0xC0,0x7F,0xE1,0xFF,0xE3,0xFF,0xC7,0xCF,0x9F,0x0F,0x9E,0x1E,0x3E,0x7C,0x7F,0xF8,0x7F,0xE0,0xFF,0xC3,0xFF,0xCF,0x87,0xDF,0x0F,0xBE,0x1F,0x7C,0x3E,0xFF,0xFC,0xFF,0xF0,0xFF,0xC0,0x7E,0x00, // '8' 31 | 0x0F,0xC0,0x3F,0xC0,0xFF,0xC3,0xFF,0xC7,0xCF,0x9F,0x0F,0xBE,0x1F,0x7C,0x3E,0xF8,0x7D,0xF8,0xF9,0xFF,0xF3,0xFF,0xE3,0xFF,0xC3,0xEF,0x00,0x3E,0x00,0xF8,0x1F,0xF0,0x3F,0xC0,0x7E,0x00,0xF0,0x00, // '9' 32 | 0x73,0xCF,0xBE,0x70,0x00,0x00,0x00,0x00,0x1C,0xF3,0xEF,0x9C, // ':' 33 | 0x38,0xF1,0xF3,0xE3,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x1E,0x3C,0x78,0xF1,0xE3,0x8E,0x0C,0x00, // ';' 34 | 0x00,0x30,0x07,0x81,0xFC,0x3F,0xEF,0xFC,0x7F,0x03,0xC0,0x1F,0xC0,0xFF,0xC0,0xFF,0x81,0xFC,0x01,0xE0,0x03,0x00, // '<' 35 | 0xFF,0xF7,0xFF,0xBF,0xFD,0xFF,0xE0,0x00,0x00,0x03,0xFF,0xDF,0xFE,0xFF,0xF7,0xFF,0x80, // '=' 36 | 0x80,0x07,0x00,0x3F,0x01,0xFE,0x07,0xFE,0x07,0xF8,0x07,0xC1,0xFE,0x7F,0xE7,0xF8,0x3F,0x01,0xC0,0x08,0x00,0x00, // '>' 37 | 0x0F,0xC0,0xFF,0xC7,0xFF,0x9F,0xFE,0xF8,0xF8,0x01,0xE0,0x0F,0x80,0x7C,0x03,0xF0,0x1F,0x00,0x78,0x01,0xE0,0x07,0x80,0x00,0x00,0x00,0x01,0xC0,0x0F,0x80,0x3E,0x00,0xF8,0x01,0xC0, // '?' 38 | 0x00,0x7F,0x00,0x03,0xFF,0xC0,0x07,0xFF,0xF0,0x0F,0x81,0xF8,0x1E,0x00,0x78,0x3C,0x00,0x1C,0x78,0x3E,0x1C,0x70,0x7F,0x8E,0x70,0xFF,0x8E,0xF1,0xE3,0x8E,0xE1,0xC7,0x8E,0xE3,0xC7,0x0E,0xE3,0x87,0x0E,0xE3,0x87,0x0E,0xE3,0x87,0x0E,0xE3,0xCF,0x1C,0xE3,0xFF,0xFC,0xF1,0xFB,0xF8,0x70,0xF1,0xE0,0x78,0x00,0x00,0x3C,0x00,0x00,0x3F,0x01,0x00,0x1F,0xFF,0x00,0x07,0xFF,0x00,0x01,0xFC,0x00, // '@' 39 | 0x01,0xF0,0x00,0x1F,0x00,0x03,0xF8,0x00,0x3F,0x80,0x03,0xF8,0x00,0x7F,0xC0,0x07,0xBC,0x00,0x7B,0xE0,0x0F,0xBE,0x00,0xF1,0xE0,0x1F,0x1F,0x01,0xF1,0xF0,0x1F,0x0F,0x03,0xFF,0xF8,0x3F,0xFF,0x83,0xFF,0xF8,0x7F,0xFF,0xC7,0xC0,0x7C,0xFC,0x07,0xEF,0x80,0x3E, // 'A' 40 | 0xFF,0xE0,0x7F,0xFE,0x3F,0xFF,0x9F,0xFF,0xCF,0x83,0xE7,0xC0,0xF3,0xE0,0x79,0xF0,0x7C,0xFF,0xFE,0x7F,0xFC,0x3F,0xFF,0x1F,0xFF,0xCF,0x83,0xF7,0xC0,0xFB,0xE0,0x7D,0xF0,0x7E,0xFF,0xFE,0x7F,0xFF,0x3F,0xFF,0x1F,0xFE,0x00, // 'B' 41 | 0x07,0xE0,0x0F,0xFC,0x0F,0xFF,0x8F,0xFF,0xC7,0xC3,0xF7,0xC0,0xFB,0xE0,0x3D,0xF0,0x00,0xF8,0x00,0x7C,0x00,0x3E,0x00,0x1F,0x00,0x0F,0x80,0x07,0xC0,0x7B,0xE0,0x7C,0xF8,0x7E,0x7F,0xFE,0x1F,0xFF,0x07,0xFF,0x00,0xFE,0x00, // 'C' 42 | 0xFF,0x80,0xFF,0xE0,0xFF,0xF0,0xFF,0xF8,0xF0,0xFC,0xF0,0x7C,0xF0,0x3E,0xF0,0x3E,0xF0,0x3E,0xF0,0x3E,0xF0,0x3E,0xF0,0x3E,0xF0,0x3E,0xF0,0x3E,0xF0,0x7C,0xF0,0xFC,0xFF,0xF8,0xFF,0xF0,0xFF,0xE0,0xFF,0x80, // 'D' 43 | 0xFF,0xFB,0xFF,0xEF,0xFF,0xBF,0xFE,0xF0,0x03,0xC0,0x0F,0x00,0x3C,0x00,0xFF,0xF3,0xFF,0xCF,0xFF,0x3F,0xFC,0xF0,0x03,0xC0,0x0F,0x00,0x3C,0x00,0xFF,0xFB,0xFF,0xEF,0xFF,0xBF,0xFE, // 'E' 44 | 0xFF,0xFB,0xFF,0xEF,0xFF,0xBF,0xFE,0xF0,0x03,0xC0,0x0F,0x00,0x3C,0x00,0xFF,0xF3,0xFF,0xCF,0xFF,0x3F,0xFC,0xF0,0x03,0xC0,0x0F,0x00,0x3C,0x00,0xF0,0x03,0xC0,0x0F,0x00,0x3C,0x00, // 'F' 45 | 0x03,0xF0,0x03,0xFF,0x03,0xFF,0xE0,0xFF,0xFC,0x7E,0x1F,0x1F,0x03,0xEF,0x80,0xFB,0xE0,0x00,0xF8,0x00,0x3E,0x1F,0xEF,0x87,0xFB,0xE1,0xFE,0xF8,0x7F,0xBE,0x03,0xE7,0xC0,0xF9,0xF8,0x3E,0x3F,0xFF,0x8F,0xFF,0xE0,0xFF,0xE0,0x0F,0xE0, // 'G' 46 | 0xF0,0x1F,0x78,0x0F,0xBC,0x07,0xDE,0x03,0xEF,0x01,0xF7,0x80,0xFB,0xC0,0x7D,0xE0,0x3E,0xFF,0xFF,0x7F,0xFF,0xBF,0xFF,0xDF,0xFF,0xEF,0x01,0xF7,0x80,0xFB,0xC0,0x7D,0xE0,0x3E,0xF0,0x1F,0x78,0x0F,0xBC,0x07,0xDE,0x03,0xE0, // 'H' 47 | 0xFB,0xEF,0xBE,0xFB,0xEF,0xBE,0xFB,0xEF,0xBE,0xFB,0xEF,0xBE,0xFB,0xEF,0xBE, // 'I' 48 | 0x00,0x78,0x01,0xE0,0x07,0x80,0x1E,0x00,0x78,0x01,0xE0,0x07,0x80,0x1E,0x00,0x78,0x01,0xE0,0x07,0x80,0x1E,0x00,0x7B,0xC1,0xEF,0x8F,0xBE,0x3E,0xFF,0xF9,0xFF,0xC3,0xFE,0x07,0xE0, // 'J' 49 | 0xF0,0x3F,0x78,0x3F,0x3C,0x1F,0x1E,0x1F,0x8F,0x1F,0x87,0x8F,0x83,0xCF,0x81,0xEF,0xC0,0xF7,0xC0,0x7F,0xE0,0x3F,0xF8,0x1F,0xFC,0x0F,0xFF,0x07,0xCF,0x83,0xE7,0xE1,0xE1,0xF8,0xF0,0x7C,0x78,0x3F,0x3C,0x0F,0x9E,0x07,0xE0, // 'K' 50 | 0xF0,0x03,0xC0,0x0F,0x00,0x3C,0x00,0xF0,0x03,0xC0,0x0F,0x00,0x3C,0x00,0xF0,0x03,0xC0,0x0F,0x00,0x3C,0x00,0xF0,0x03,0xC0,0x0F,0x00,0x3C,0x00,0xFF,0xFB,0xFF,0xEF,0xFF,0xBF,0xFE, // 'L' 51 | 0xFC,0x01,0xFB,0xF0,0x0F,0xEF,0xE0,0x3F,0xBF,0x80,0xFE,0xFE,0x07,0xFB,0xFC,0x1F,0xEF,0xF0,0x77,0xBF,0xC3,0xDE,0xF7,0x8F,0x7B,0xDE,0x3B,0xEF,0x79,0xEF,0xBC,0xE7,0xBE,0xF3,0xDC,0xFB,0xCF,0xF3,0xEF,0x1F,0xCF,0xBC,0x7E,0x3E,0xF1,0xF8,0xFB,0xC3,0xE3,0xEF,0x0F,0x0F,0xBC,0x3C,0x3E, // 'M' 52 | 0xF8,0x0F,0x7C,0x07,0xBF,0x03,0xDF,0xC1,0xEF,0xE0,0xF7,0xF8,0x7B,0xFC,0x3D,0xFF,0x1E,0xFF,0x8F,0x7D,0xE7,0xBE,0xF3,0xDF,0x3D,0xEF,0x9F,0xF7,0xC7,0xFB,0xE3,0xFD,0xF0,0xFE,0xF8,0x3F,0x7C,0x1F,0xBE,0x07,0xDF,0x03,0xE0, // 'N' 53 | 0x07,0xE0,0x07,0xFE,0x03,0xFF,0xE1,0xFF,0xF8,0x7E,0x3F,0x3F,0x07,0xCF,0x80,0xFB,0xE0,0x3E,0xF8,0x0F,0xBE,0x03,0xEF,0x80,0xFB,0xE0,0x3E,0xF8,0x0F,0xBE,0x03,0xEF,0xC1,0xF9,0xF8,0xFC,0x7F,0xFF,0x0F,0xFF,0x81,0xFF,0xC0,0x1F,0xC0, // 'O' 54 | 0xFF,0xE0,0x7F,0xFC,0x3F,0xFF,0x9F,0xFF,0xCF,0x83,0xF7,0xC0,0xFB,0xE0,0x7D,0xF0,0x3E,0xF8,0x3F,0x7F,0xFF,0x3F,0xFF,0x9F,0xFF,0x8F,0xFF,0x07,0xC0,0x03,0xE0,0x01,0xF0,0x00,0xF8,0x00,0x7C,0x00,0x3E,0x00,0x1F,0x00,0x00, // 'P' 55 | 0x07,0xE0,0x07,0xFE,0x03,0xFF,0xE1,0xFF,0xF8,0x7E,0x3F,0x3F,0x07,0xCF,0x80,0xFB,0xE0,0x3E,0xF8,0x0F,0xBE,0x03,0xEF,0x80,0xFB,0xE0,0x3E,0xF8,0x0F,0xBE,0x03,0xEF,0xC1,0xF9,0xF8,0xFC,0x7F,0xFF,0x0F,0xFF,0x81,0xFF,0xC0,0x1F,0xF8,0x00,0x3F,0x80,0x03,0xC0,0x00,0x60, // 'Q' 56 | 0xFF,0xF0,0x7F,0xFE,0x3F,0xFF,0x9F,0xFF,0xCF,0x83,0xF7,0xC0,0xFB,0xE0,0x7D,0xF0,0x3E,0xF8,0x3E,0x7F,0xFF,0x3F,0xFF,0x1F,0xFF,0x0F,0xFF,0x87,0xC7,0xC3,0xE1,0xF1,0xF0,0xF8,0xF8,0x3E,0x7C,0x1F,0x3E,0x07,0xDF,0x03,0xE0, // 'R' 57 | 0x07,0xE0,0x0F,0xFC,0x0F,0xFF,0x8F,0xFF,0xC7,0xC3,0xF3,0xE0,0xF9,0xF0,0x00,0xFE,0x00,0x3F,0xE0,0x0F,0xFC,0x03,0xFF,0x00,0x3F,0xC0,0x03,0xF7,0xC0,0xFB,0xE0,0x7D,0xF8,0x7E,0x7F,0xFE,0x1F,0xFF,0x07,0xFF,0x00,0xFE,0x00, // 'S' 58 | 0xFF,0xFF,0x7F,0xFF,0xBF,0xFF,0xDF,0xFF,0xE0,0x7C,0x00,0x3E,0x00,0x1F,0x00,0x0F,0x80,0x07,0xC0,0x03,0xE0,0x01,0xF0,0x00,0xF8,0x00,0x7C,0x00,0x3E,0x00,0x1F,0x00,0x0F,0x80,0x07,0xC0,0x03,0xE0,0x01,0xF0,0x00,0xF8,0x00, // 'T' 59 | 0xF0,0x1E,0xF0,0x1E,0xF0,0x1E,0xF0,0x1E,0xF0,0x1E,0xF0,0x1E,0xF0,0x1E,0xF0,0x1E,0xF0,0x1E,0xF0,0x1E,0xF0,0x1E,0xF0,0x1E,0xF0,0x1E,0xF8,0x3E,0xF8,0x3E,0xFC,0x7E,0xFF,0xFE,0x7F,0xFC,0x3F,0xF8,0x0F,0xE0, // 'U' 60 | 0xFC,0x07,0xE7,0xC0,0x7C,0x7C,0x07,0xC7,0xC0,0xFC,0x3E,0x0F,0x83,0xE0,0xF8,0x3E,0x0F,0x81,0xF1,0xF0,0x1F,0x1F,0x01,0xF1,0xF0,0x0F,0x1E,0x00,0xFB,0xE0,0x0F,0xBE,0x00,0x7B,0xC0,0x07,0xFC,0x00,0x7F,0xC0,0x03,0xF8,0x00,0x3F,0x80,0x03,0xF8,0x00,0x1F,0x00, // 'V' 61 | 0xF8,0x3C,0x1F,0x7C,0x1E,0x0F,0x9E,0x1F,0x87,0x8F,0x8F,0xC7,0xC7,0xC7,0xE3,0xE3,0xE3,0xF1,0xF0,0xF3,0xF8,0xF0,0x79,0xFE,0x78,0x3C,0xFF,0x7C,0x1F,0x7F,0xBE,0x0F,0xBF,0xDF,0x03,0xFC,0xFF,0x01,0xFE,0x7F,0x80,0xFF,0x3F,0xC0,0x7F,0x9F,0xE0,0x3F,0x87,0xF0,0x0F,0xC3,0xF0,0x07,0xE1,0xF8,0x03,0xF0,0xFC,0x01,0xF0,0x7E,0x00, // 'W' 62 | 0xFC,0x0F,0xCF,0x83,0xF0,0xF8,0x7C,0x1F,0x1F,0x81,0xF3,0xE0,0x3E,0xFC,0x03,0xFF,0x00,0x7F,0xC0,0x07,0xF8,0x00,0x7E,0x00,0x1F,0xC0,0x03,0xFC,0x00,0xFF,0xC0,0x1F,0xF8,0x07,0xCF,0x80,0xF9,0xF0,0x3E,0x1F,0x0F,0xC3,0xE1,0xF0,0x3E,0x7E,0x07,0xE0, // 'X' 63 | 0xF8,0x0F,0xCF,0x81,0xF1,0xF0,0x7C,0x1F,0x0F,0x83,0xE1,0xE0,0x3C,0x7C,0x07,0xCF,0x00,0x7B,0xE0,0x0F,0xF8,0x00,0xFF,0x00,0x1F,0xC0,0x01,0xF8,0x00,0x3E,0x00,0x07,0xC0,0x00,0xF8,0x00,0x1F,0x00,0x03,0xE0,0x00,0x7C,0x00,0x0F,0x80,0x01,0xF0,0x00, // 'Y' 64 | 0xFF,0xFE,0xFF,0xFE,0xFF,0xFE,0xFF,0xFE,0x00,0x7C,0x00,0xF8,0x00,0xF8,0x01,0xF0,0x03,0xE0,0x07,0xC0,0x07,0xC0,0x0F,0x80,0x1F,0x00,0x1F,0x00,0x3E,0x00,0x7C,0x00,0xFF,0xFE,0xFF,0xFE,0xFF,0xFE,0xFF,0xFE, // 'Z' 65 | 0xFE,0xFE,0xFE,0xFE,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xFE,0xFE,0xFE,0xFE, // '[' 66 | 0xF8,0x03,0xE0,0x07,0x80,0x1F,0x00,0x7C,0x00,0xF8,0x03,0xE0,0x07,0x80,0x1F,0x00,0x7C,0x00,0xF0,0x03,0xE0,0x0F,0x80,0x1F,0x00,0x7C,0x00,0xF0,0x03,0xE0,0x0F,0x80,0x1F,0x00,0x7C,0x01,0xF0,0x03,0xE0, // '\' 67 | 0xFD,0xFB,0xF7,0xE3,0xC7,0x8F,0x1E,0x3C,0x78,0xF1,0xE3,0xC7,0x8F,0x1E,0x3C,0x78,0xF1,0xE3,0xC7,0x8F,0x1E,0xFD,0xFB,0xF7,0xE0, // ']' 68 | 0x0E,0x01,0xF0,0x1F,0x03,0xF8,0x3B,0x83,0xB8,0x79,0xC7,0x1C,0xF1,0xEE,0x0E, // '^' 69 | 0xFF,0xF7,0xFF,0xBF,0xFC, // '_' 70 | 0xF8,0x7C,0x3E,0x1E, // '`' 71 | 0x0F,0x80,0xFF,0x87,0xFF,0x3F,0xFC,0xF8,0xF8,0x03,0xE1,0xFF,0x9F,0xFE,0xFF,0xFB,0xE3,0xEF,0x0F,0xBF,0xFE,0xFF,0xF9,0xFF,0xE3,0xEF,0x80, // 'a' 72 | 0xF8,0x01,0xF0,0x03,0xE0,0x07,0xC0,0x0F,0x80,0x1F,0x00,0x3E,0xF8,0x7F,0xF8,0xFF,0xF9,0xFF,0xF3,0xF1,0xF7,0xC3,0xEF,0x87,0xDF,0x07,0xBE,0x1F,0x7C,0x3E,0xFC,0x7D,0xFF,0xFB,0xFF,0xE7,0xFF,0x8F,0xBE,0x00, // 'b' 73 | 0x0F,0xC0,0xFF,0x87,0xFF,0x1F,0xFE,0xF8,0xFB,0xE1,0xEF,0x80,0x3E,0x00,0xF8,0x03,0xE0,0x0F,0x8F,0x9F,0xFE,0x7F,0xF0,0xFF,0x80,0xFC,0x00, // 'c' 74 | 0x00,0x7C,0x00,0xF8,0x01,0xF0,0x03,0xE0,0x07,0xC0,0x0F,0x87,0xDF,0x1F,0xFE,0x7F,0xFD,0xFF,0xFB,0xE3,0xF7,0xC3,0xEF,0x07,0xDE,0x0F,0xBC,0x1F,0x7C,0x3E,0xF8,0xFC,0xFF,0xF9,0xFF,0xF1,0xFF,0xE1,0xF7,0xC0, // 'd' 75 | 0x0F,0xC0,0x7F,0xC1,0xFF,0xC3,0xFF,0xCF,0x87,0x9F,0x0F,0xBF,0xFF,0x7F,0xFE,0xFF,0xFD,0xF0,0x03,0xF0,0xC3,0xFF,0xC7,0xFF,0x87,0xFE,0x03,0xF0,0x00, // 'e' 76 | 0x07,0xC1,0xF8,0x7F,0x1F,0xE3,0xE0,0x7C,0x3F,0xF7,0xFE,0xFF,0xDF,0xF8,0xF8,0x1F,0x03,0xE0,0x7C,0x0F,0x81,0xF0,0x3E,0x07,0xC0,0xF8,0x1F,0x03,0xE0, // 'f' 77 | 0x1F,0x7C,0x7F,0xF9,0xFF,0xF7,0xFF,0xEF,0x87,0xDF,0x0F,0xBC,0x1F,0x78,0x3E,0xF0,0x7D,0xF0,0xFB,0xE1,0xF7,0xFF,0xE7,0xFF,0xC7,0xFF,0x87,0xDF,0x00,0x3E,0x30,0xF8,0xFF,0xF1,0xFF,0xC1,0xFF,0x00,0xF8,0x00, // 'g' 78 | 0xF8,0x01,0xF0,0x03,0xE0,0x07,0xC0,0x0F,0x80,0x1F,0x00,0x3E,0xF8,0x7F,0xF8,0xFF,0xF9,0xFF,0xF3,0xE3,0xF7,0xC3,0xEF,0x87,0xDF,0x0F,0xBE,0x1F,0x7C,0x3E,0xF8,0x7D,0xF0,0xFB,0xE1,0xF7,0xC3,0xEF,0x87,0xC0, // 'h' 79 | 0x78,0xF3,0xF3,0xC7,0x80,0x00,0x3C,0x78,0xF1,0xE3,0xC7,0x8F,0x1E,0x3C,0x78,0xF1,0xE3,0xC7,0x8F,0x00, // 'i' 80 | 0x1E,0x0F,0x0F,0xC3,0xC1,0xE0,0x00,0x00,0x3C,0x1E,0x0F,0x07,0x83,0xC1,0xE0,0xF0,0x78,0x3C,0x1E,0x0F,0x07,0x83,0xC1,0xE0,0xF0,0x78,0x7C,0xFE,0x7F,0x3F,0x1E,0x00, // 'j' 81 | 0xF8,0x00,0xF8,0x00,0xF8,0x00,0xF8,0x00,0xF8,0x00,0xF8,0x00,0xF8,0xFC,0xF8,0xF8,0xF9,0xF0,0xFB,0xE0,0xFF,0xE0,0xFF,0xC0,0xFF,0x80,0xFF,0xC0,0xFF,0xE0,0xFF,0xE0,0xF9,0xF0,0xF9,0xF8,0xF8,0xF8,0xF8,0x7C,0xF8,0x7E, // 'k' 82 | 0xF7,0xBD,0xEF,0x7B,0xDE,0xF7,0xBD,0xEF,0x7B,0xDE,0xF7,0xBD,0xEF,0x00, // 'l' 83 | 0xF9,0xE1,0xE1,0xFF,0xEF,0xF3,0xFF,0xFF,0xE7,0xFF,0xFF,0xCF,0x8F,0xC7,0xDF,0x0F,0x0F,0xBE,0x1E,0x1F,0x7C,0x3C,0x3E,0xF8,0x78,0x7D,0xF0,0xF0,0xFB,0xE1,0xE1,0xF7,0xC3,0xC3,0xEF,0x87,0x87,0xDF,0x0F,0x0F,0xBE,0x1E,0x1F,0x00, // 'm' 84 | 0xFB,0xE1,0xFF,0xF3,0xFF,0xE7,0xFF,0xCF,0x87,0xDF,0x0F,0xBE,0x1F,0x7C,0x3E,0xF8,0x7D,0xF0,0xFB,0xE1,0xF7,0xC3,0xEF,0x87,0xDF,0x0F,0xBE,0x1F,0x00, // 'n' 85 | 0x0F,0xC0,0x7F,0xC1,0xFF,0xC3,0xFF,0xCF,0x8F,0xDF,0x0F,0xBC,0x1F,0x78,0x3E,0xF0,0x7D,0xF0,0xFB,0xE3,0xF3,0xFF,0xC7,0xFF,0x87,0xFE,0x03,0xF0,0x00, // 'o' 86 | 0xFB,0xE1,0xFF,0xE3,0xFF,0xE7,0xFF,0xCF,0xC7,0xDF,0x0F,0xBE,0x1F,0x7C,0x1E,0xF8,0x7D,0xF0,0xFB,0xF1,0xF7,0xFF,0xCF,0xFF,0x9F,0xFE,0x3E,0xF8,0x7C,0x00,0xF8,0x01,0xF0,0x03,0xE0,0x07,0xC0,0x0F,0x80,0x00, // 'p' 87 | 0x1F,0x7C,0x7F,0xF9,0xFF,0xF7,0xFF,0xEF,0x8F,0xDF,0x0F,0xBC,0x1F,0x78,0x3E,0xF0,0x7D,0xF0,0xFB,0xE3,0xF7,0xFF,0xE7,0xFF,0xC7,0xFF,0x87,0xDF,0x00,0x3E,0x00,0x7C,0x00,0xF8,0x01,0xF0,0x03,0xE0,0x07,0xC0, // 'q' 88 | 0xF7,0xBF,0xEF,0xF3,0xFC,0xF8,0x3C,0x0F,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x3C,0x0F,0x00, // 'r' 89 | 0x0F,0xC0,0xFF,0xC7,0xFF,0x9F,0xFE,0x78,0xF9,0xE0,0x07,0xFC,0x0F,0xFC,0x0F,0xF8,0x03,0xEF,0x87,0x9F,0xFE,0x7F,0xF8,0xFF,0xC0,0xFC,0x00, // 's' 90 | 0x3E,0x0F,0x83,0xE0,0xF8,0xFF,0xBF,0xEF,0xFB,0xFE,0x3E,0x0F,0x83,0xE0,0xF8,0x3E,0x0F,0x83,0xE0,0xFE,0x3F,0x87,0xE0,0xF8, // 't' 91 | 0xF8,0x7D,0xF0,0xFB,0xE1,0xF7,0xC3,0xEF,0x87,0xDF,0x0F,0xBE,0x1F,0x7C,0x3E,0xF8,0x7D,0xF0,0xFB,0xE3,0xF3,0xFF,0xE7,0xFF,0xCF,0xFF,0x87,0xDF,0x00, // 'u' 92 | 0xF8,0x7D,0xF0,0xF9,0xE1,0xE3,0xE7,0xC7,0xCF,0x87,0x9E,0x0F,0x3C,0x1E,0xF8,0x1F,0xE0,0x3F,0xC0,0x7F,0x80,0x7E,0x00,0xFC,0x01,0xF8,0x03,0xF0,0x00, // 'v' 93 | 0xF8,0xF1,0xF7,0xC7,0x8F,0x1E,0x3C,0x78,0xF3,0xF3,0xC7,0x9F,0x9E,0x3C,0xFD,0xF0,0xF7,0xEF,0x07,0xFF,0xF8,0x3F,0x9F,0xC1,0xFC,0xFE,0x07,0xE7,0xE0,0x3F,0x3F,0x01,0xF0,0xF8,0x0F,0x87,0xC0,0x3C,0x3C,0x00, // 'w' 94 | 0xF8,0x7C,0xF8,0xF0,0xF3,0xE1,0xF7,0x81,0xFF,0x03,0xFC,0x03,0xF8,0x07,0xE0,0x0F,0xE0,0x3F,0xC0,0x7F,0xC1,0xF7,0xC7,0xCF,0x8F,0x8F,0xBE,0x1F,0x00, // 'x' 95 | 0xF8,0x3E,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x3C,0x78,0x3E,0xF8,0x3E,0xF8,0x1E,0xF0,0x1F,0xF0,0x0F,0xF0,0x0F,0xE0,0x0F,0xE0,0x07,0xE0,0x07,0xC0,0x07,0xC0,0x07,0xC0,0x0F,0x80,0x3F,0x80,0x3F,0x00,0x3F,0x00,0x3C,0x00, // 'y' 96 | 0xFF,0xF7,0xFF,0xBF,0xFD,0xFF,0xE0,0x3E,0x03,0xE0,0x3E,0x01,0xF0,0x1F,0x01,0xF0,0x1F,0x01,0xFF,0xEF,0xFF,0x7F,0xFB,0xFF,0xC0, // 'z' 97 | 0x06,0x07,0x07,0xC7,0x83,0xC1,0xE0,0xF0,0x78,0x3C,0x1E,0x0F,0x0F,0x0F,0x87,0x03,0xE0,0xF0,0x3C,0x1E,0x0F,0x07,0x83,0xC1,0xE0,0xF0,0x78,0x1E,0x07,0x81,0x80, // '{' 98 | 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE, // '|' 99 | 0xC0,0x70,0x3C,0x0F,0x07,0x83,0xC1,0xE0,0xF0,0x78,0x3C,0x1E,0x07,0x83,0xF0,0x78,0xFC,0x78,0x78,0x3C,0x1E,0x0F,0x07,0x83,0xC1,0xE0,0xF0,0xF0,0x70,0x30,0x00 // '}' 100 | }; 101 | const GFXglyph Roboto_Black_28Glyphs[] PROGMEM = { 102 | // bitmapOffset, width, height, xAdvance, xOffset, yOffset 103 | { 0, 1, 1, 8, 0, 0 }, // ' ' 104 | { 1, 6, 20, 9, 2, -20 }, // '!' 105 | { 16, 9, 8, 10, 0, -21 }, // '"' 106 | { 25, 17, 20, 17, 0, -20 }, // '#' 107 | { 68, 15, 26, 17, 1, -23 }, // '$' 108 | { 117, 20, 20, 22, 1, -20 }, // '%' 109 | { 167, 18, 20, 20, 1, -20 }, // '&' 110 | { 212, 5, 8, 5, 0, -21 }, // ''' 111 | { 217, 8, 28, 11, 2, -22 }, // '(' 112 | { 245, 9, 28, 11, 1, -22 }, // ')' 113 | { 277, 14, 12, 14, 0, -20 }, // '*' 114 | { 298, 14, 14, 16, 1, -16 }, // '+' 115 | { 323, 6, 9, 9, 1, -3 }, // ',' 116 | { 330, 9, 4, 14, 2, -10 }, // '-' 117 | { 335, 6, 5, 9, 2, -5 }, // '.' 118 | { 339, 11, 22, 11, 0, -20 }, // '/' 119 | { 370, 15, 20, 17, 1, -20 }, // '0' 120 | { 408, 10, 20, 17, 2, -20 }, // '1' 121 | { 433, 15, 20, 17, 1, -20 }, // '2' 122 | { 471, 15, 20, 17, 1, -20 }, // '3' 123 | { 509, 15, 20, 17, 1, -20 }, // '4' 124 | { 547, 15, 20, 17, 1, -20 }, // '5' 125 | { 585, 15, 20, 17, 1, -20 }, // '6' 126 | { 623, 15, 20, 17, 1, -20 }, // '7' 127 | { 661, 15, 20, 17, 1, -20 }, // '8' 128 | { 699, 15, 20, 17, 1, -20 }, // '9' 129 | { 737, 6, 16, 9, 2, -16 }, // ':' 130 | { 749, 7, 22, 9, 1, -16 }, // ';' 131 | { 769, 13, 13, 15, 1, -15 }, // '<' 132 | { 791, 13, 10, 17, 2, -13 }, // '=' 133 | { 808, 13, 13, 15, 2, -15 }, // '>' 134 | { 830, 14, 20, 15, 0, -20 }, // '?' 135 | { 865, 24, 25, 26, 1, -19 }, // '@' 136 | { 940, 20, 20, 20, 0, -20 }, // 'A' 137 | { 990, 17, 20, 19, 1, -20 }, // 'B' 138 | { 1033, 17, 20, 19, 1, -20 }, // 'C' 139 | { 1076, 16, 20, 19, 2, -20 }, // 'D' 140 | { 1116, 14, 20, 17, 2, -20 }, // 'E' 141 | { 1151, 14, 20, 16, 2, -20 }, // 'F' 142 | { 1186, 18, 20, 20, 1, -20 }, // 'G' 143 | { 1231, 17, 20, 21, 2, -20 }, // 'H' 144 | { 1274, 6, 20, 9, 2, -20 }, // 'I' 145 | { 1289, 14, 20, 17, 1, -20 }, // 'J' 146 | { 1324, 17, 20, 19, 2, -20 }, // 'K' 147 | { 1367, 14, 20, 16, 2, -20 }, // 'L' 148 | { 1402, 22, 20, 26, 2, -20 }, // 'M' 149 | { 1457, 17, 20, 21, 2, -20 }, // 'N' 150 | { 1500, 18, 20, 20, 1, -20 }, // 'O' 151 | { 1545, 17, 20, 19, 1, -20 }, // 'P' 152 | { 1588, 18, 23, 20, 1, -20 }, // 'Q' 153 | { 1640, 17, 20, 19, 1, -20 }, // 'R' 154 | { 1683, 17, 20, 19, 1, -20 }, // 'S' 155 | { 1726, 17, 20, 19, 1, -20 }, // 'T' 156 | { 1769, 16, 20, 20, 2, -20 }, // 'U' 157 | { 1809, 20, 20, 20, 0, -20 }, // 'V' 158 | { 1859, 25, 20, 25, 0, -20 }, // 'W' 159 | { 1922, 19, 20, 19, 0, -20 }, // 'X' 160 | { 1970, 19, 20, 19, 0, -20 }, // 'Y' 161 | { 2018, 16, 20, 18, 1, -20 }, // 'Z' 162 | { 2058, 8, 28, 9, 1, -23 }, // '[' 163 | { 2086, 14, 22, 13, 0, -20 }, // '\' 164 | { 2125, 7, 28, 9, 0, -23 }, // ']' 165 | { 2150, 12, 10, 14, 1, -20 }, // '^' 166 | { 2165, 13, 3, 13, 0, 0 }, // '_' 167 | { 2170, 8, 4, 11, 1, -21 }, // '`' 168 | { 2174, 14, 15, 16, 1, -15 }, // 'a' 169 | { 2201, 15, 21, 17, 1, -21 }, // 'b' 170 | { 2241, 14, 15, 16, 1, -15 }, // 'c' 171 | { 2268, 15, 21, 17, 1, -21 }, // 'd' 172 | { 2308, 15, 15, 16, 1, -15 }, // 'e' 173 | { 2337, 11, 21, 11, 0, -21 }, // 'f' 174 | { 2366, 15, 21, 17, 1, -15 }, // 'g' 175 | { 2406, 15, 21, 17, 1, -21 }, // 'h' 176 | { 2446, 7, 22, 9, 1, -22 }, // 'i' 177 | { 2466, 9, 28, 9, -1, -22 }, // 'j' 178 | { 2498, 16, 21, 16, 1, -21 }, // 'k' 179 | { 2540, 5, 21, 9, 2, -21 }, // 'l' 180 | { 2554, 23, 15, 25, 1, -15 }, // 'm' 181 | { 2598, 15, 15, 17, 1, -15 }, // 'n' 182 | { 2627, 15, 15, 17, 1, -15 }, // 'o' 183 | { 2656, 15, 21, 17, 1, -15 }, // 'p' 184 | { 2696, 15, 21, 17, 1, -15 }, // 'q' 185 | { 2736, 10, 15, 12, 2, -15 }, // 'r' 186 | { 2755, 14, 15, 15, 0, -15 }, // 's' 187 | { 2782, 10, 19, 11, 0, -19 }, // 't' 188 | { 2806, 15, 15, 17, 1, -15 }, // 'u' 189 | { 2835, 15, 15, 15, 0, -15 }, // 'v' 190 | { 2864, 21, 15, 21, 0, -15 }, // 'w' 191 | { 2904, 15, 15, 15, 0, -15 }, // 'x' 192 | { 2933, 16, 21, 16, 0, -15 }, // 'y' 193 | { 2975, 13, 15, 15, 1, -15 }, // 'z' 194 | { 3000, 9, 27, 10, 1, -22 }, // '{' 195 | { 3031, 4, 24, 8, 2, -20 }, // '|' 196 | { 3043, 9, 27, 10, 1, -22 } // '}' 197 | }; 198 | const GFXfont Roboto_Black_28 PROGMEM = { 199 | (uint8_t *)Roboto_Black_28Bitmaps,(GFXglyph *)Roboto_Black_28Glyphs,0x20, 0x7E, 33}; 200 | 201 | -------------------------------------------------------------------------------- /linux/epd_demo/main.c: -------------------------------------------------------------------------------- 1 | // 2 | // WaveShare 2.7" e-paper HAT demo 3 | // The same hardware connection numbers should work 4 | // on other WaveShare hats 5 | // 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | //#include "../../src/OneBitDisplay.cpp" 13 | #include "Roboto_Black_28.h" 14 | 15 | OBDISP epd; 16 | 17 | #define EPD_FREQ 4000000 18 | // header pin numbers, NOT BCM 19 | #define INKY_CS 24 20 | #define INKY_BUSY 18 21 | #define INKY_DC 22 22 | #define INKY_RES 11 23 | #define FLIP180 0 24 | #define INVERT 0 25 | #define BITBANG 0 26 | 27 | int main(int argc, char **argv) 28 | { 29 | int i; 30 | 31 | printf("Starting...\n"); 32 | i = AIOInitBoard("Raspberry Pi"); 33 | if (i == 0) // problem 34 | { 35 | printf("Error in AIOInitBoard(); check if this board is supported\n"); 36 | return 0; 37 | } 38 | 39 | obdSPIInit(&epd, EPD27_176x264, INKY_DC, INKY_CS, INKY_RES, -1, -1, INKY_BUSY, FLIP180, INVERT, BITBANG, EPD_FREQ); 40 | obdSetRotation(&epd, 90); 41 | obdAllocBuffer(&epd); 42 | obdFill(&epd, 0, 0); 43 | obdWriteString(&epd, 0,0,0,(char *)"WaveShare 2.7\" e-paper", FONT_12x16, OBD_BLACK, 0); 44 | obdWriteString(&epd, 0,0,16,(char *)"OneBitDisplay lib in C", FONT_12x16,OBD_BLACK,0); 45 | obdEllipse(&epd,epd.width/2, epd.height/2, 40,40,OBD_BLACK,1); 46 | obdWriteStringCustom(&epd, (GFXfont *)&Roboto_Black_28, 0,epd.height, (char *)"Custom fonts too", OBD_BLACK); 47 | obdDumpBuffer(&epd, NULL); // do a full update 48 | printf("Display done\n"); 49 | return 0; 50 | } /* main() */ 51 | 52 | -------------------------------------------------------------------------------- /linux/gif_1_bus_2_oleds/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-c -Wall -O3 -D__LINUX__ -D_LINUX_ 2 | 3 | all: gifplay 4 | 5 | gifplay: main.o 6 | $(CC) main.o -o gifplay 7 | 8 | main.o: main.c ../../src/obd.inl ../../src/OneBitDisplay.h 9 | $(CC) $(CFLAGS) main.c 10 | 11 | clean: 12 | rm -rf *.o gifplay 13 | -------------------------------------------------------------------------------- /linux/gif_1_bus_2_oleds/main.c: -------------------------------------------------------------------------------- 1 | // 2 | // main.c 3 | // OneBitDisplay library test program 4 | // 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "../../../AnimatedGIF/src/AnimatedGIF.h" 17 | #include "../../../AnimatedGIF/src/gif.inl" 18 | #include "../../src/OneBitDisplay.cpp" 19 | #include "running_256_64.h" 20 | 21 | #define OLED_TYPE OLED_132x64 22 | #define OLED_ADDR 0x3c 23 | #define FLIP180 0 24 | #define INVERT 0 25 | #define HW_I2C 1 26 | // On Linux this is the I2C bus number (SDA_PIN) for HW I2C 27 | #define SDA_PIN 1 28 | // On Linux this is the I2C device address 29 | #define SCL_PIN 0x3c 30 | #define RESET_PIN -1 31 | // This is not controlled on Linux through the API 32 | // On the Raspberry PI, see /boot/config.txt 33 | #define SPEED 0 34 | #define DISPLAY_WIDTH 256 35 | #define DISPLAY_HEIGHT 64 36 | static uint8_t ucOLED_0[1024], ucOLED_1[1024]; 37 | static OBDISP obd[2]; 38 | // 39 | // This doesn't have to be super efficient 40 | // 41 | void DrawPixel(int x, int y, uint8_t ucColor) 42 | { 43 | uint8_t *d, ucMask; 44 | 45 | ucMask = 1 << (y & 7); 46 | if (x >= 128) // right display 47 | d = &ucOLED_1[(x-128)+((y>>3) << 7)]; 48 | else 49 | d = &ucOLED_0[x + ((y>>3) << 7)]; 50 | if (ucColor) 51 | *d |= ucMask; 52 | else 53 | *d &= ~ucMask; 54 | } 55 | 56 | // Draw a line of image into our 1-bpp virtual display buffers 57 | void GIFDraw(GIFDRAW *pDraw) 58 | { 59 | uint8_t *s; 60 | int x, y, iWidth; 61 | static uint8_t ucPalette[256]; // thresholded palette 62 | 63 | if (pDraw->y == 0) // first line, convert palette to 0/1 64 | { 65 | for (x = 0; x < 256; x++) 66 | { 67 | uint16_t usColor = pDraw->pPalette[x]; 68 | int gray = (usColor & 0xf800) >> 8; // red 69 | gray += ((usColor & 0x7e0) >> 2); // plus green*2 70 | gray += ((usColor & 0x1f) << 3); // plus blue 71 | ucPalette[x] = (gray >> 9); // 0->511 = 0, 512->1023 = 1 72 | } 73 | } 74 | y = pDraw->iY + pDraw->y; // current line 75 | iWidth = pDraw->iWidth; 76 | if (iWidth > DISPLAY_WIDTH) 77 | iWidth = DISPLAY_WIDTH; 78 | 79 | s = pDraw->pPixels; 80 | if (pDraw->ucDisposalMethod == 2) // restore to background color 81 | { 82 | for (x=0; xucTransparent) 85 | s[x] = pDraw->ucBackground; 86 | } 87 | pDraw->ucHasTransparency = 0; 88 | } 89 | // Apply the new pixels to the main image 90 | if (pDraw->ucHasTransparency) // if transparency used 91 | { 92 | uint8_t c, ucTransparent = pDraw->ucTransparent; 93 | int x; 94 | for(x=0; x < iWidth; x++) 95 | { 96 | c = *s++; 97 | if (c != ucTransparent) 98 | DrawPixel(pDraw->iX + x, y, ucPalette[c]); 99 | } 100 | } 101 | else 102 | { 103 | s = pDraw->pPixels; 104 | // Translate the 8-bit pixels through the RGB565 palette (already byte reversed) 105 | for (x=0; xiWidth; x++) 106 | DrawPixel(pDraw->iX + x, y, ucPalette[*s++]); 107 | } 108 | if (pDraw->y == pDraw->iHeight-1) { // last line, render it to the display(s) 109 | obdDumpBuffer(&obd[0], NULL); 110 | obdDumpBuffer(&obd[1], NULL); 111 | } 112 | } /* GIFDraw() */ 113 | 114 | int main(int argc, const char * argv[]) 115 | { 116 | GIFIMAGE gif; 117 | int rc; 118 | int iDelay; 119 | 120 | obdI2CInit(&obd[0], OLED_TYPE, -1, FLIP180, INVERT, HW_I2C, 1, 0x3C, RESET_PIN, SPEED); 121 | obdSetBackBuffer(&obd[0], ucOLED_0); 122 | obdFill(&obd[0], 0, 1); 123 | obdI2CInit(&obd[1], OLED_TYPE, -1, FLIP180, INVERT, HW_I2C, 1, 0x3D, RESET_PIN, SPEED); 124 | obdSetBackBuffer(&obd[1], ucOLED_1); 125 | obdFill(&obd[1], 0, 1); 126 | GIF_begin(&gif, GIF_PALETTE_RGB565_LE); 127 | while (1) { 128 | rc = GIF_openRAM(&gif, (uint8_t *)running_256_64, sizeof(running_256_64), GIFDraw); 129 | if (rc) { 130 | while (GIF_playFrame(&gif, &iDelay, NULL)) { 131 | // usleep(iDelay * 1000); 132 | } 133 | } 134 | } // while (1) 135 | return 0; 136 | } /* main() */ 137 | -------------------------------------------------------------------------------- /linux/obd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #define OUTPUT GPIO_OUT 11 | #define INPUT GPIO_IN 12 | #define INPUT_PULLUP GPIO_IN_PULLUP 13 | #define HIGH 1 14 | #define LOW 0 15 | #include "../src/OneBitDisplay.h" 16 | #include "../src/obd.inl" 17 | 18 | -------------------------------------------------------------------------------- /linux/sharp_fast_gif/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-c -Wall -O3 -D__LINUX__ -D_LINUX_ -DSPI_BUS_NUMBER=0 2 | LIBS = -lpthread -larmbianio 3 | all: gifplay 4 | 5 | gifplay: main.o 6 | $(CC) main.o $(LIBS) -o gifplay 7 | 8 | main.o: main.c ../../src/obd.inl ../../src/OneBitDisplay.h 9 | $(CC) $(CFLAGS) main.c 10 | 11 | clean: 12 | rm -rf *.o gifplay 13 | -------------------------------------------------------------------------------- /linux/sharp_fast_gif/main.c: -------------------------------------------------------------------------------- 1 | // 2 | // main.c 3 | // OneBitDisplay library test program 4 | // 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "../../../AnimatedGIF/src/AnimatedGIF.h" 19 | #include "../../../AnimatedGIF/src/gif.inl" 20 | #include "../../src/OneBitDisplay.cpp" 21 | #include "pattern_400x240.h" 22 | 23 | #define DISPLAY_TYPE SHARP_400x240 24 | #define FLIP180 0 25 | #define INVERT 0 26 | #define DC_PIN -1 27 | #define CS_PIN 16 28 | #define DISP_PIN 18 29 | #define EXTCOM_PIN 22 30 | #define RESET_PIN -1 31 | #define SPEED 8000000 32 | #define BITBANG 0 33 | #define LED_PIN -1 34 | 35 | // This is not controlled on Linux through the API 36 | // On the Raspberry PI, see /boot/config.txt 37 | #define DISPLAY_WIDTH 400 38 | #define DISPLAY_HEIGHT 240 39 | #define DISPLAY_PITCH ((DISPLAY_WIDTH>>3)+2) 40 | static uint8_t ucBuffer[(DISPLAY_PITCH * DISPLAY_HEIGHT)+2]; 41 | static OBDISP obd; 42 | volatile int iStop = 0; 43 | 44 | void my_handler(int signal) 45 | { 46 | iStop = 1; 47 | } /* my_handler() */ 48 | 49 | // 50 | // This doesn't have to be super efficient 51 | // 52 | void DrawPixel(int x, int y, uint8_t ucColor) 53 | { 54 | uint8_t *d, ucMask; 55 | 56 | ucMask = 0x80 >> (x & 7); 57 | d = &ucBuffer[2 + (x>>3) + (y*DISPLAY_PITCH)]; 58 | if (ucColor) 59 | *d &= ~ucMask; 60 | else 61 | *d |= ucMask; 62 | } 63 | 64 | // Draw a line of image into our 1-bpp virtual display buffers 65 | void GIFDraw(GIFDRAW *pDraw) 66 | { 67 | uint8_t *s, *d = &ucBuffer[2]; 68 | int x, y, iWidth; 69 | int iX = pDraw->iX; 70 | static uint8_t ucPalette[256]; // thresholded palette 71 | 72 | if (pDraw->y == 0) // first line, convert palette to 0/1 73 | { 74 | for (x = 0; x < 256; x++) 75 | { 76 | uint16_t usColor = pDraw->pPalette[x]; 77 | int gray = (usColor & 0xf800) >> 8; // red 78 | gray += ((usColor & 0x7e0) >> 2); // plus green*2 79 | gray += ((usColor & 0x1f) << 3); // plus blue 80 | ucPalette[x] = (gray >> 9); // 0->511 = 0, 512->1023 = 1 81 | } 82 | } 83 | y = pDraw->iY + pDraw->y; // current line 84 | d += (y * DISPLAY_PITCH); 85 | iWidth = pDraw->iWidth; 86 | if (iWidth > DISPLAY_WIDTH) 87 | iWidth = DISPLAY_WIDTH; 88 | 89 | s = pDraw->pPixels; 90 | if (pDraw->ucDisposalMethod == 2) // restore to background color 91 | { 92 | for (x=0; xucTransparent) 95 | s[x] = pDraw->ucBackground; 96 | } 97 | pDraw->ucHasTransparency = 0; 98 | } 99 | // Apply the new pixels to the main image 100 | if (pDraw->ucHasTransparency) // if transparency used 101 | { 102 | uint8_t c, ucTransparent = pDraw->ucTransparent; 103 | int x; 104 | for(x=0; x < iWidth; x++) 105 | { 106 | c = *s++; 107 | if (c != ucTransparent) { 108 | // DrawPixel(iX + x, y, ucPalette[c]); 109 | if (ucPalette[c]) d[((iX+x)>>3)] |= (0x80 >> ((iX+x)&7)); 110 | else d[((iX+x)>>3)] &= ~(0x80 >> ((iX+x)&7)); 111 | } 112 | } 113 | } 114 | else 115 | { 116 | s = pDraw->pPixels; 117 | // Translate the 8-bit pixels through the RGB565 palette (already byte reversed) 118 | for (x=0; xiWidth; x++) { 119 | if (ucPalette[*s++]) d[((iX+x)>>3)] |= (0x80 >> ((iX+x)&7)); 120 | else d[((iX+x)>>3)] &= ~(0x80 >> ((iX+x)&7)); 121 | //DrawPixel(pDraw->iX + x, y, ucPalette[*s++]); 122 | } 123 | } 124 | if (pDraw->y == pDraw->iHeight-1) { // last line, render it to the display 125 | // obdDumpBuffer(&obd, NULL); 126 | AIOWriteGPIO(CS_PIN, HIGH); 127 | ucBuffer[0] ^= 0x40; // toggle VCOM bit 128 | AIOWriteSPI(obd.bbi2c.file_i2c, ucBuffer, sizeof(ucBuffer)); 129 | // RawWriteData(&obd, ucBuffer, sizeof(ucBuffer)); 130 | AIOWriteGPIO(CS_PIN, LOW); 131 | } 132 | } /* GIFDraw() */ 133 | 134 | // Less efficient than a lookup table, but it's only used at init time 135 | // This saves a couple hundred bytes of FLASH 136 | uint8_t MirrorBits(uint8_t v) 137 | { 138 | uint8_t r = v & 1; 139 | uint8_t s = 7; 140 | for (v >>= 1; v; v >>= 1) { 141 | r <<= 1; 142 | r |= (v & 1); 143 | s--; 144 | } 145 | r <<= s; // adjust for 0's 146 | return r; 147 | } /* MirrorBits() */ 148 | 149 | void PrepBuffer(void) 150 | { 151 | uint8_t *d; 152 | int i; 153 | 154 | d = ucBuffer; 155 | *d++ = 0x80; // start byte 156 | for (i=0; i 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "../../../AnimatedGIF/src/AnimatedGIF.h" 19 | #include "../../../AnimatedGIF/src/gif.inl" 20 | #include "../../src/OneBitDisplay.cpp" 21 | #include "pattern_400x240.h" 22 | 23 | #define DISPLAY_TYPE SHARP_400x240 24 | #define FLIP180 0 25 | #define INVERT 0 26 | #define DC_PIN -1 27 | #define CS_PIN 16 28 | #define DISP_PIN 18 29 | #define EXTCOM_PIN 22 30 | #define RESET_PIN -1 31 | #define SPEED 8000000 32 | #define BITBANG 0 33 | #define LED_PIN -1 34 | 35 | // This is not controlled on Linux through the API 36 | // On the Raspberry PI, see /boot/config.txt 37 | #define DISPLAY_WIDTH 400 38 | #define DISPLAY_HEIGHT 240 39 | static uint8_t ucBuffer[12000]; 40 | static OBDISP obd; 41 | volatile int iStop = 0; 42 | 43 | void my_handler(int signal) 44 | { 45 | iStop = 1; 46 | } /* my_handler() */ 47 | 48 | // 49 | // This doesn't have to be super efficient 50 | // 51 | void DrawPixel(int x, int y, uint8_t ucColor) 52 | { 53 | uint8_t *d, ucMask; 54 | 55 | ucMask = 1 << (y & 7); 56 | d = &ucBuffer[x + ((y>>3) * DISPLAY_WIDTH)]; 57 | if (ucColor) 58 | *d &= ~ucMask; 59 | else 60 | *d |= ucMask; 61 | } 62 | 63 | // Draw a line of image into our 1-bpp virtual display buffers 64 | void GIFDraw(GIFDRAW *pDraw) 65 | { 66 | uint8_t *s; 67 | int x, y, iWidth; 68 | static uint8_t ucPalette[256]; // thresholded palette 69 | 70 | if (pDraw->y == 0) // first line, convert palette to 0/1 71 | { 72 | for (x = 0; x < 256; x++) 73 | { 74 | uint16_t usColor = pDraw->pPalette[x]; 75 | int gray = (usColor & 0xf800) >> 8; // red 76 | gray += ((usColor & 0x7e0) >> 2); // plus green*2 77 | gray += ((usColor & 0x1f) << 3); // plus blue 78 | ucPalette[x] = (gray >> 9); // 0->511 = 0, 512->1023 = 1 79 | } 80 | } 81 | y = pDraw->iY + pDraw->y; // current line 82 | iWidth = pDraw->iWidth; 83 | if (iWidth > DISPLAY_WIDTH) 84 | iWidth = DISPLAY_WIDTH; 85 | 86 | s = pDraw->pPixels; 87 | if (pDraw->ucDisposalMethod == 2) // restore to background color 88 | { 89 | for (x=0; xucTransparent) 92 | s[x] = pDraw->ucBackground; 93 | } 94 | pDraw->ucHasTransparency = 0; 95 | } 96 | // Apply the new pixels to the main image 97 | if (pDraw->ucHasTransparency) // if transparency used 98 | { 99 | uint8_t c, ucTransparent = pDraw->ucTransparent; 100 | int x; 101 | for(x=0; x < iWidth; x++) 102 | { 103 | c = *s++; 104 | if (c != ucTransparent) 105 | DrawPixel(pDraw->iX + x, y, ucPalette[c]); 106 | } 107 | } 108 | else 109 | { 110 | s = pDraw->pPixels; 111 | // Translate the 8-bit pixels through the RGB565 palette (already byte reversed) 112 | for (x=0; xiWidth; x++) 113 | DrawPixel(pDraw->iX + x, y, ucPalette[*s++]); 114 | } 115 | if (pDraw->y == pDraw->iHeight-1) { // last line, render it to the display 116 | obdDumpBuffer(&obd, NULL); 117 | } 118 | } /* GIFDraw() */ 119 | 120 | int main(int argc, const char * argv[]) 121 | { 122 | GIFIMAGE gif; 123 | int rc; 124 | int iDelay; 125 | struct sigaction sigIntHandler; 126 | 127 | // Set CTRL-C signal handler 128 | sigIntHandler.sa_handler = my_handler; 129 | sigemptyset(&sigIntHandler.sa_mask); 130 | sigIntHandler.sa_flags = 0; 131 | sigaction(SIGINT, &sigIntHandler, NULL); 132 | 133 | printf("Sharp Memory LCD GIF demo\n"); 134 | printf("Press Ctrl-C to quit\n"); 135 | 136 | rc = AIOInitBoard("Raspberry Pi"); 137 | if (rc == 0) // problem 138 | { 139 | printf("Error in AIOInit(); check if this board is supported\n"); 140 | return 0; 141 | } 142 | AIOAddGPIO(DISP_PIN, OUTPUT); // enable display 143 | AIOWriteGPIO(DISP_PIN, HIGH); 144 | AIOAddGPIO(EXTCOM_PIN, OUTPUT); 145 | 146 | obdSPIInit(&obd, DISPLAY_TYPE, DC_PIN, CS_PIN, RESET_PIN, -1, -1, LED_PIN, FLIP180, INVERT, BITBANG, SPEED); 147 | obdSetBackBuffer(&obd, ucBuffer); 148 | obdFill(&obd, 0, 0); 149 | obdDumpBuffer(&obd, NULL); 150 | GIF_begin(&gif, GIF_PALETTE_RGB565_LE); 151 | while (!iStop) { 152 | rc = GIF_openRAM(&gif, (uint8_t *)pattern_400x240, sizeof(pattern_400x240), GIFDraw); 153 | if (rc) { 154 | while (GIF_playFrame(&gif, &iDelay, NULL)) { 155 | //usleep(iDelay * 1000); 156 | } 157 | } else { 158 | printf("GIF decode error = %d\n", gif.iError); 159 | iStop = 1; 160 | } 161 | } // while (1) 162 | AIOWriteGPIO(DISP_PIN, LOW); // turn off LCD 163 | AIOShutdown(); 164 | 165 | return 0; 166 | } /* main() */ 167 | -------------------------------------------------------------------------------- /linux/spi_demo/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-c -Wall -O2 -DSPI_BUS_NUMBER=0 -D_LINUX_ 2 | LIBS = -lpthread -larmbianio 3 | all: spi_demo 4 | 5 | spi_demo: main.o 6 | $(CC) main.o $(LIBS) -o spi_demo 7 | 8 | main.o: main.c ../../src/obd.inl ../../src/OneBitDisplay.cpp ../../src/OneBitDisplay.h 9 | $(CC) $(CFLAGS) main.c 10 | 11 | clean: 12 | rm -rf *.o spi_demo 13 | -------------------------------------------------------------------------------- /linux/spi_demo/main.c: -------------------------------------------------------------------------------- 1 | // 2 | // main.c 3 | // OneBitDisplay library test program 4 | // Demonstrates many of the features for OLED displays 5 | // 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "../../src/OneBitDisplay.cpp" 19 | 20 | volatile int iStop = 0; 21 | 22 | //#define OLED_TYPE OLED_132x64 23 | //#define OLED_TYPE LCD_UC1609 24 | #define OLED_TYPE LCD_UC1701 25 | #define FLIP180 0 26 | #define INVERT 0 27 | #define DC_PIN 22 28 | #define CS_PIN -1 29 | //#define CS_PIN 24 30 | #define RESET_PIN 13 31 | #define SPEED 4000000 32 | #define BITBANG 0 33 | // LED on GPIO 12 34 | #define LED_PIN 32 35 | OBDISP obd; 36 | static uint8_t ucBuffer[1024]; 37 | 38 | void my_handler(int signal) 39 | { 40 | iStop = 1; 41 | } /* my_handler() */ 42 | 43 | int main(int argc, const char *argv[]) 44 | { 45 | int i; 46 | struct sigaction sigIntHandler; 47 | //size_t ret; 48 | 49 | // Set CTRL-C signal handler 50 | sigIntHandler.sa_handler = my_handler; 51 | sigemptyset(&sigIntHandler.sa_mask); 52 | sigIntHandler.sa_flags = 0; 53 | sigaction(SIGINT, &sigIntHandler, NULL); 54 | 55 | i = AIOInitBoard("Raspberry Pi"); 56 | if (i == 0) // problem 57 | { 58 | printf("Error in AIOInit(); check if this board is supported\n"); 59 | return 0; 60 | } 61 | 62 | //void obdSPIInit(OBDISP *pOBD, int iType, int iDC, int iCS, int iReset, int iMOSI, int iCLK, int iLED, int bFlip, int bInvert, int bBitBang, int32_t iSpeed) 63 | obdSPIInit(&obd, OLED_TYPE, DC_PIN, CS_PIN, RESET_PIN, -1, -1, LED_PIN, FLIP180, INVERT, BITBANG, SPEED); 64 | obdSetBackBuffer(&obd, ucBuffer); 65 | // Create some simple content 66 | obdFill(&obd, 0, 1); 67 | obdSetContrast(&obd, 63); // white on black requires max contrast to be visible 68 | obdBacklight(&obd, 1); 69 | obdWriteString(&obd,0,0,0,"OneBitDisplay", FONT_8x8, 0, 1); 70 | while (!iStop) { 71 | obdFill(&obd, 0, 1); 72 | for (int i=0; i<128; i++) { 73 | obdDrawLine(&obd, i, 0, 127-i, 63, 1, 1); 74 | } 75 | for (int i=0; i<64; i++) { 76 | obdDrawLine(&obd, 127, i, 0, 63-i, 1, 1); 77 | } 78 | } 79 | // obdEllipse(&obd, 320, 240+64, 150,100, 0, 1); 80 | // obdRectangle(&obd, 300, 240+32, 340, 240+96, 1, 1); 81 | obdFill(&obd, 0, 1); 82 | obdBacklight(&obd, 0); 83 | AIOShutdown(); 84 | return 0; 85 | } /* main() */ 86 | -------------------------------------------------------------------------------- /linux/virtual_disp/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-c -Wall -O3 -D_LINUX_ 2 | 3 | all: obd_test 4 | 5 | obd_test: main.o 6 | $(CC) main.o -o obd_test 7 | 8 | main.o: main.c ../../src/obd.inl ../../src/OneBitDisplay.h 9 | $(CC) $(CFLAGS) main.c 10 | 11 | clean: 12 | rm -rf *.o obd_test 13 | -------------------------------------------------------------------------------- /linux/virtual_disp/main.c: -------------------------------------------------------------------------------- 1 | // 2 | // main.c 3 | // OneBitDisplay library test program 4 | // 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "../../src/OneBitDisplay.h" 17 | #include "../../src/obd.inl" 18 | #include "../../examples/prop_font_demo/FreeSerif12pt7b.h" 19 | #include "notes.h" 20 | 21 | void WriteBMP(const char *name, uint8_t *pData, int width, int height, int bpp) 22 | { 23 | int bsize, lsize, i, iHeaderSize, iBodySize; 24 | uint8_t pBuf[128]; // holds BMP header 25 | FILE *outfile; 26 | 27 | bsize = width >> 3; 28 | lsize = (bsize + 3) & 0xfffc; // DWORD aligned 29 | iHeaderSize = 54; 30 | iHeaderSize += (1<<(bpp+2)); 31 | iBodySize = lsize * height; 32 | i = iBodySize + iHeaderSize; // datasize 33 | memset(pBuf, 0, 54); 34 | pBuf[0] = 'B'; 35 | pBuf[1] = 'M'; 36 | pBuf[2] = i & 0xff; // 4 bytes of file size 37 | pBuf[3] = (i >> 8) & 0xff; 38 | pBuf[4] = (i >> 16) & 0xff; 39 | pBuf[5] = (i >> 24) & 0xff; 40 | /* Offset to data bits */ 41 | pBuf[10] = iHeaderSize & 0xff; 42 | pBuf[11] = (unsigned char)(iHeaderSize >> 8); 43 | pBuf[14] = 0x28; 44 | pBuf[18] = width & 0xff; // xsize low 45 | pBuf[19] = (unsigned char)(width >> 8); // xsize high 46 | i = -height; // top down bitmap 47 | pBuf[22] = i & 0xff; // ysize low 48 | pBuf[23] = (unsigned char)(i >> 8); // ysize high 49 | pBuf[24] = 0xff; 50 | pBuf[25] = 0xff; 51 | pBuf[26] = 1; // number of planes 52 | pBuf[28] = (uint8_t)bpp; 53 | pBuf[30] = 0; // uncompressed 54 | i = iBodySize; 55 | pBuf[34] = i & 0xff; // data size 56 | pBuf[35] = (i >> 8) & 0xff; 57 | pBuf[36] = (i >> 16) & 0xff; 58 | pBuf[37] = (i >> 24) & 0xff; 59 | pBuf[54] = pBuf[55] = pBuf[56] = pBuf[57] = pBuf[61] = 0; // palette 60 | pBuf[58] = pBuf[59] = pBuf[60] = 0xff; 61 | outfile = fopen((char *)name, "w+b"); 62 | if (outfile) 63 | { 64 | uint8_t *s = pData; 65 | fwrite(pBuf, 1, iHeaderSize, outfile); 66 | for (i=0; i> 3; 89 | pBitonal = malloc(out_pitch * height); 90 | pOut = malloc(out_pitch * height); 91 | 92 | obdCreateVirtualDisplay(&obd, width, height, pBitonal); 93 | // Create some simple content 94 | obdFill(&obd, 0xff, 1); // colors are inverted 95 | obdWriteString(&obd,0,0,0,"OneBitDisplay test program", FONT_12x16, 1, 1); 96 | obdWriteString(&obd,0,0,2,"Written to vertify fonts and GFX", FONT_16x16, 1, 1); 97 | obdWriteString(&obd,0,0,4,"This is the 8x8 fixed font", FONT_8x8, 1, 1); 98 | obdWriteString(&obd,0,0,5,"This is the smallest (6x8) font", FONT_6x8, 1, 1); 99 | obdWriteString(&obd,0,0,6,"This is the largest built-in font", FONT_16x32, 1, 1); 100 | obdWriteStringCustom(&obd, (GFXfont *)&FreeSerif12pt7b, 0, 100, (char *)"Custom (Adafruit_GFX format) fonts are supported too",0); 101 | for (int i=0; i<640; i+=8) { 102 | obdDrawLine(&obd, i, 128, 640-i, 479, 0, 0); 103 | } 104 | obdEllipse(&obd, 320, 240+64, 150,100, 0, 1); 105 | obdRectangle(&obd, 300, 240+32, 340, 240+96, 1, 1); 106 | obdLoadBMP(&obd, (uint8_t *)notes, 15, 240, 0); 107 | obdCopy(&obd, OBD_ROTATE_90 | OBD_MSB_FIRST | OBD_HORZ_BYTES | OBD_FLIP_VERT | OBD_FLIP_HORZ, pOut); 108 | WriteBMP(argv[1], pOut, height, width, 1); 109 | free(pOut); 110 | free(pBitonal); 111 | return 0; 112 | } /* main() */ 113 | -------------------------------------------------------------------------------- /linux/virtual_disp/notes.h: -------------------------------------------------------------------------------- 1 | // 2 | // notes 3 | // Data size = 2386 bytes 4 | // 5 | // OS/2 BMP, Compression=None, Size: 100 x 140, 1-Bpp 6 | // 7 | // for non-Arduino builds... 8 | #ifndef PROGMEM 9 | #define PROGMEM 10 | #endif 11 | const uint8_t notes[] PROGMEM = { 12 | 0x42,0x4d,0x52,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x92,0x00,0x00,0x00,0x7c,0x00, 13 | 0x00,0x00,0x64,0x00,0x00,0x00,0x8c,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x03,0x00, 14 | 0x00,0x00,0xc0,0x08,0x00,0x00,0x13,0x0b,0x00,0x00,0x13,0x0b,0x00,0x00,0x02,0x00, 15 | 0x00,0x00,0x02,0x00,0x00,0x00,0x00,0xf8,0x00,0x00,0xe0,0x07,0x00,0x00,0x1f,0x00, 16 | 0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x47,0x52,0x73,0x00,0x00,0x00,0x00,0x00,0x00, 17 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 18 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 19 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00, 20 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, 21 | 0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 22 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 23 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 24 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 25 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 26 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 27 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 28 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 29 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 30 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 31 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 32 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 33 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 34 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0xff,0xff,0xff,0xf0,0x00, 35 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x00,0x3f,0xff,0xff,0xf0,0x00, 36 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x00,0x0f,0xff,0xff,0xf0,0x00, 37 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x80,0x00,0x03,0xff,0xff,0xf0,0x00, 38 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x01,0xff,0xff,0xf0,0x00, 39 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x00,0x00,0x00,0xff,0xff,0xf0,0x00, 40 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x00,0x00,0x00,0x7f,0xff,0xf0,0x00, 41 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x00,0x00,0x00,0x3f,0xff,0xf0,0x00, 42 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x00,0x00,0x00,0x3f,0xff,0xf0,0x00, 43 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00,0x00,0x00,0x1f,0xff,0xf0,0x00, 44 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00,0x00,0x00,0x1f,0xff,0xf0,0x00, 45 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00,0x00,0x00,0x0f,0xff,0xf0,0x00, 46 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x00,0x00,0x00,0x0f,0xff,0xf0,0x00, 47 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x00,0x00,0x00,0x0f,0xff,0xf0,0x00, 48 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x00,0x00,0x00,0x07,0xff,0xf0,0x00, 49 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x00,0x00,0x00,0x07,0xff,0xf0,0x00, 50 | 0x00,0x00,0xff,0xff,0xfc,0x00,0xff,0xff,0xe0,0x00,0x00,0x00,0x07,0xff,0xf0,0x00, 51 | 0x00,0x00,0xff,0xff,0xe0,0x00,0x3f,0xff,0xf0,0x00,0x00,0x00,0x03,0xff,0xf0,0x00, 52 | 0x00,0x00,0xff,0xff,0x80,0x00,0x0f,0xff,0xf0,0x00,0x00,0x00,0x03,0xff,0xf0,0x00, 53 | 0x00,0x00,0xff,0xff,0x00,0x00,0x03,0xff,0xf0,0x00,0x00,0x00,0x03,0xff,0xf0,0x00, 54 | 0x00,0x00,0xff,0xfe,0x00,0x00,0x01,0xff,0xf8,0x00,0x00,0x00,0x03,0xff,0xf0,0x00, 55 | 0x00,0x00,0xff,0xfc,0x00,0x00,0x00,0xff,0xf8,0x00,0x00,0x00,0x01,0xff,0xf0,0x00, 56 | 0x00,0x00,0xff,0xf8,0x00,0x00,0x00,0xff,0xfc,0x00,0x00,0x00,0x01,0xff,0xf0,0x00, 57 | 0x00,0x00,0xff,0xf0,0x00,0x00,0x00,0x7f,0xfc,0x00,0x00,0x00,0x41,0xff,0xf0,0x00, 58 | 0x00,0x00,0xff,0xf0,0x00,0x00,0x00,0x3f,0xfe,0x00,0x00,0x00,0xc1,0xff,0xf0,0x00, 59 | 0x00,0x00,0xff,0xe0,0x00,0x00,0x00,0x3f,0xff,0x00,0x00,0x01,0xc1,0xff,0xf0,0x00, 60 | 0x00,0x00,0xff,0xe0,0x00,0x00,0x00,0x3f,0xff,0xc0,0x00,0x07,0xc1,0xff,0xf0,0x00, 61 | 0x00,0x00,0xff,0xe0,0x00,0x00,0x00,0x1f,0xff,0xf0,0x00,0x1f,0xc1,0xff,0xf0,0x00, 62 | 0x00,0x00,0xff,0xe0,0x00,0x00,0x00,0x1f,0xff,0xfc,0x00,0x7f,0xc1,0xff,0xf0,0x00, 63 | 0x00,0x00,0xff,0xe0,0x00,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 64 | 0x00,0x00,0xff,0xc0,0x00,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 65 | 0x00,0x00,0xff,0xe0,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 66 | 0x00,0x00,0xff,0xe0,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 67 | 0x00,0x00,0xff,0xe0,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 68 | 0x00,0x00,0xff,0xe0,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 69 | 0x00,0x00,0xff,0xf0,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 70 | 0x00,0x00,0xff,0xf0,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 71 | 0x00,0x00,0xff,0xf8,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 72 | 0x00,0x00,0xff,0xf8,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 73 | 0x00,0x00,0xff,0xfc,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 74 | 0x00,0x00,0xff,0xfe,0x00,0x00,0x02,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 75 | 0x00,0x00,0xff,0xff,0x00,0x00,0x06,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 76 | 0x00,0x00,0xff,0xff,0xc0,0x00,0x0e,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 77 | 0x00,0x00,0xff,0xff,0xf0,0x00,0x3e,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 78 | 0x00,0x00,0xff,0xff,0xfe,0x01,0xfe,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 79 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 80 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 81 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 82 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 83 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 84 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 85 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 86 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 87 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 88 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 89 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0xe0,0xff,0xf0,0x00, 90 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0xe1,0xff,0xf0,0x00, 91 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0xe1,0xff,0xf0,0x00, 92 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0xe1,0xff,0xf0,0x00, 93 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0xc1,0xff,0xf0,0x00, 94 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0xc1,0xff,0xf0,0x00, 95 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0xc1,0xff,0xf0,0x00, 96 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0xc1,0xff,0xf0,0x00, 97 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0xc1,0xff,0xf0,0x00, 98 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0xc1,0xff,0xf0,0x00, 99 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0xc1,0xff,0xf0,0x00, 100 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0xc1,0xff,0xf0,0x00, 101 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0xc1,0xff,0xf0,0x00, 102 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0xc3,0xff,0xf0,0x00, 103 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0x83,0xff,0xf0,0x00, 104 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0x83,0xff,0xf0,0x00, 105 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x0f,0xff,0xff,0xff,0xff,0x83,0xff,0xf0,0x00, 106 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x1f,0xff,0xff,0xff,0xff,0x83,0xff,0xf0,0x00, 107 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfe,0x1f,0xff,0xff,0xff,0xff,0x83,0xff,0xf0,0x00, 108 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfc,0x1f,0xff,0xff,0xff,0xfc,0x03,0xff,0xf0,0x00, 109 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfc,0x1f,0xff,0xff,0xff,0xe0,0x07,0xff,0xf0,0x00, 110 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfc,0x1f,0xff,0xff,0xff,0x00,0x07,0xff,0xf0,0x00, 111 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfc,0x1f,0xff,0xff,0xf8,0x00,0x07,0xff,0xf0,0x00, 112 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfc,0x1f,0xff,0xff,0xe0,0x00,0x07,0xff,0xf0,0x00, 113 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfc,0x1f,0xff,0xff,0x00,0x03,0x07,0xff,0xf0,0x00, 114 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfc,0x1f,0xff,0xfc,0x00,0x1f,0x07,0xff,0xf0,0x00, 115 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfc,0x1f,0xff,0xf0,0x00,0xfe,0x0f,0xff,0xf0,0x00, 116 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfc,0x3f,0xff,0xc0,0x03,0xfe,0x0f,0xff,0xf0,0x00, 117 | 0x00,0x00,0xff,0xff,0xff,0xff,0xfc,0x3f,0xff,0x00,0x1f,0xfe,0x0f,0xff,0xf0,0x00, 118 | 0x00,0x00,0xff,0xff,0xff,0xff,0xf8,0x3f,0xfe,0x00,0x7f,0xfe,0x0f,0xff,0xf0,0x00, 119 | 0x00,0x00,0xff,0xff,0xff,0xff,0xf8,0x3f,0xf8,0x01,0xff,0xfc,0x1f,0xff,0xf0,0x00, 120 | 0x00,0x00,0xff,0xff,0xff,0xff,0xf8,0x3f,0xe0,0x07,0xff,0xc0,0x1f,0xff,0xf0,0x00, 121 | 0x00,0x00,0xff,0xff,0xff,0xff,0xf8,0x3f,0xc0,0x1f,0xfe,0x00,0x1f,0xff,0xf0,0x00, 122 | 0x00,0x00,0xff,0xff,0xff,0xff,0xf8,0x3f,0x00,0x7f,0xf0,0x00,0x3f,0xff,0xf0,0x00, 123 | 0x00,0x00,0xff,0xff,0xff,0xff,0xf8,0x3e,0x00,0xff,0xc0,0x00,0x7f,0xff,0xf0,0x00, 124 | 0x00,0x00,0xff,0xff,0xff,0xff,0xf8,0x78,0x03,0xfe,0x00,0x07,0xff,0xff,0xf0,0x00, 125 | 0x00,0x00,0xff,0xff,0xff,0xff,0xf8,0x70,0x0f,0xf8,0x00,0x3f,0xff,0xff,0xf0,0x00, 126 | 0x00,0x00,0xff,0xff,0xff,0xff,0xf0,0x40,0x1f,0xe0,0x01,0xff,0xff,0xff,0xf0,0x00, 127 | 0x00,0x00,0xff,0xff,0xff,0xff,0xf0,0x00,0x7f,0x80,0x0f,0xff,0xff,0xff,0xf0,0x00, 128 | 0x00,0x00,0xff,0xff,0xff,0xff,0xf0,0x00,0xfe,0x00,0x3f,0xff,0xff,0xff,0xf0,0x00, 129 | 0x00,0x00,0xff,0xff,0xff,0xff,0xf0,0x03,0xf8,0x00,0xff,0xff,0xff,0xff,0xf0,0x00, 130 | 0x00,0x00,0xff,0xff,0xff,0xff,0xf0,0x07,0xf0,0x03,0xff,0xff,0xff,0xff,0xf0,0x00, 131 | 0x00,0x00,0xff,0xff,0xff,0xff,0xf0,0x1f,0xc0,0x0f,0xff,0xff,0xff,0xff,0xf0,0x00, 132 | 0x00,0x00,0xff,0xff,0xff,0xff,0xe0,0x3f,0x00,0x3f,0xff,0xff,0xff,0xff,0xf0,0x00, 133 | 0x00,0x00,0xff,0xff,0xff,0xff,0xe0,0xfe,0x00,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 134 | 0x00,0x00,0xff,0xff,0xff,0xff,0xe0,0xf8,0x03,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 135 | 0x00,0x00,0xff,0xff,0xff,0xff,0xe0,0xe0,0x0f,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 136 | 0x00,0x00,0xff,0xff,0xff,0xff,0xe0,0xc0,0x1f,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 137 | 0x00,0x00,0xff,0xff,0xff,0xff,0xe1,0x00,0x7f,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 138 | 0x00,0x00,0xff,0xff,0xff,0xff,0xc0,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 139 | 0x00,0x00,0xff,0xff,0xff,0xff,0xc0,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 140 | 0x00,0x00,0xff,0xff,0xff,0xff,0xc0,0x07,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 141 | 0x00,0x00,0xff,0xff,0xff,0xff,0xc0,0x1f,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 142 | 0x00,0x00,0xff,0xff,0xff,0xff,0xc0,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 143 | 0x00,0x00,0xff,0xff,0xff,0xff,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 144 | 0x00,0x00,0xff,0xff,0xff,0xff,0xc1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 145 | 0x00,0x00,0xff,0xff,0xff,0xff,0xe7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 146 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 147 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 148 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 149 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 150 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 151 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 152 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 153 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 154 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 155 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 156 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 157 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 158 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 159 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 160 | 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00, 161 | 0x00,0x00}; 162 | -------------------------------------------------------------------------------- /notes.txt: -------------------------------------------------------------------------------- 1 | Technical Notes: 2 | ---------------- 3 | 4 | I2C 5 | --- 6 | Since adding the obdCachededWrite feature to reduce the number of I2C transactions 7 | when drawing fixed fonts, I discovered the limitations of the Wire library. On AVR 8 | targets the wire library allows a maximum write length of 32 bytes in a single call. 9 | Any data beyond the 32 bytes is not sent. The ESP32 has a similar behavior, but the 10 | limit is 128 bytes. OneBitDisplay tests for this condition in the write wrapper function 11 | and breaks up a data write into 32-byte pieces if it's being sent to hardware I2C. 12 | The bit-bang I2C doesn't have this limitation, so the write length is unlimited. 13 | 14 | BLE 15 | --- 16 | Getting BLE to work on both ESP32 and the Arduino hardware like the Nano 33 BLE was 17 | challenging not only because of the different API, but a fundamental difference in 18 | behavior. Sending fast data is hindered when the write() requests a response. On ESP32 19 | the writeValue() method allows you to choose if you want a response or not, but on 20 | the ArduinoBLE library (for the Nano 33 BLE), it will choose to wait for a response 21 | when the characteristic offers both properties. I added a new overloaded function to 22 | the ArduinoBLE library to allow you to choose. I created a pull request on Github and 23 | hope that Arduino will eventually merge the code: 24 | 25 | https://github.com/arduino-libraries/ArduinoBLE/pull/72 26 | 27 | UART 28 | ---- 29 | Sending the SSD1306 commands over a UART presented new challenges. With I2C and 30 | BLE there are well defined "packets" because a transmission begins and ends. 31 | This is necessary for this type of data stream because a single byte tells the 32 | display controller to interpret the following bytes as commands or graphics. 33 | If there is no boundary between one packet and the next, the controller will 34 | misinterpret the start byte as a command or graphics from the previous packet. 35 | This is the exact problem with transmission over a UART because the way the 36 | data is read on the receiving end doesn't necessarily correspond with the way 37 | it's transmitted. To solve this problem, I added additional code on the 38 | sending side to add a length byte in front of each packet and on the receiving 39 | end I added code to re-sync the data if the length+D/C bytes don't line up 40 | properly. 41 | -------------------------------------------------------------------------------- /sharp_lcd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitbank2/OneBitDisplay/5c5e1b9c2ebd08a63e66c39460514a9d811bb921/sharp_lcd.jpg -------------------------------------------------------------------------------- /src/obd_io.inl: -------------------------------------------------------------------------------- 1 | // 2 | // OneBitDisplay (OLED/LCD/E-Paper library) 3 | // Copyright (c) 2020 BitBank Software, Inc. 4 | // Written by Larry Bank (bitbank@pobox.com) 5 | // Project started 3/23/2020 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | // I/O functions for the OneBitDisplay library 18 | // 19 | // This define (WIMPY_MCU) precludes the use of hardware interfaces 20 | // such as I2C & SPI 21 | // 22 | #if defined (__AVR_ATtiny85__) || defined (ARDUINO_ARCH_MCS51) 23 | #define WIMPY_MCU 24 | #endif 25 | 26 | #define MAX_CACHE 192 27 | static uint8_t u8Cache[MAX_CACHE]; // for faster character drawing 28 | static volatile uint8_t u8End = 0; 29 | static uint8_t u8Temp[40]; // for stretched character drawing 30 | 31 | #ifdef _LINUX_ 32 | #define PROGMEM 33 | #define false 0 34 | #define true 1 35 | #define LOW 0 36 | #define HIGH 1 37 | #ifndef I2C_SLAVE 38 | #define I2C_SLAVE 0 39 | #define INPUT GPIO_IN 40 | #define OUTPUT GPIO_OUT 41 | #define INPUT_PULLUP GPIO_IN_PULLUP 42 | #define HIGH 1 43 | #define LOW 0 44 | #endif 45 | #if defined(_LINUX_) || defined(ARDUINO_ARCH_MCS51) 46 | #define memcpy_P memcpy 47 | #endif 48 | 49 | void obdSetDCMode(OBDISP *pOBD, int iMode); 50 | static uint8_t pgm_read_byte(const uint8_t *ptr); 51 | static void digitalWrite(int iPin, int iState) { 52 | #ifndef MEMORY_ONLY 53 | AIOWriteGPIO(iPin, iState); 54 | #endif 55 | } 56 | static void pinMode(int iPin, int iMode) 57 | { 58 | #ifndef MEMORY_ONLY 59 | AIOAddGPIO(iPin, iMode); 60 | #endif 61 | } /* pinMode() */ 62 | static void delayMicroseconds(int iTime) 63 | { 64 | usleep(iTime); 65 | } /* delayMicroseconds() */ 66 | static int digitalRead(int iPin) 67 | { 68 | return AIOReadGPIO(iPin); 69 | } /* digitalRead() */ 70 | #endif // _LINUX_ 71 | 72 | #if !defined( _LINUX_ ) && !defined( WIMPY_MCU ) 73 | #include 74 | 75 | #ifdef ARDUINO_ARCH_RP2040 76 | MbedSPI *mySPI; 77 | #else 78 | SPIClass *mySPI = &SPI; 79 | #endif 80 | #endif // !_LINUX_ 81 | 82 | // Initialize SPI 83 | void initSPI(OBDISP *pOBD, int iSpeed, int iMOSI, int iCLK, int iCS) 84 | { 85 | #ifdef WIMPY_MCU 86 | (void)iSpeed; (void)iMOSI; (void)iCLK; (void)iCS; 87 | #endif 88 | 89 | if (pOBD->bBitBang) 90 | return; 91 | #ifdef _LINUX_ 92 | pOBD->bbi2c.file_i2c = AIOOpenSPI(SPI_BUS_NUMBER, iSpeed); 93 | #elif defined ( ARDUINO_ARCH_RP2040 ) 94 | if (iMOSI == -1 || iMOSI == 0xff) { 95 | iMOSI = MOSI; iCLK = SCK; // use the default pins 96 | } 97 | mySPI = new MbedSPI(-1,iMOSI,iCLK); 98 | mySPI->begin(); 99 | #elif defined( ARDUINO_ARCH_ESP32 ) || defined( RISCV ) 100 | if (iMOSI != -1 && iMOSI != 0xff) { 101 | mySPI->begin(iCLK, -1, iMOSI, iCS); 102 | } else { 103 | mySPI->begin(); 104 | } 105 | #elif !defined (WIMPY_MCU) // simple (default pin) SPI 106 | (void)iMOSI; (void)iCLK; (void)iCS; 107 | mySPI->begin(); 108 | mySPI->beginTransaction(SPISettings(iSpeed, MSBFIRST, SPI_MODE0)); 109 | #ifndef ARDUINO_ARCH_NRF52 110 | mySPI->endTransaction(); // N.B. - if you call beginTransaction() again without a matching endTransaction(), it will hang on ESP32 111 | // BUT!!! if you do call endTransaction on NRF52, it won't send any data at all 112 | #endif 113 | #endif // _LINUX_ 114 | } /* initSPI() */ 115 | 116 | // 117 | // Bit Bang the data on GPIO pins 118 | // 119 | void SPI_BitBang(OBDISP *pOBD, uint8_t *pData, int iLen, uint8_t iMOSIPin, uint8_t iSCKPin) 120 | { 121 | int i; 122 | uint8_t c; 123 | 124 | // We can access the GPIO ports much quicker on AVR by directly manipulating 125 | // the port registers 126 | #ifdef __AVR__ 127 | volatile uint8_t *outSCK, *outMOSI; // port registers for fast I/O 128 | uint8_t port, bitSCK, bitMOSI; // bit mask for the chosen pins 129 | 130 | port = digitalPinToPort(iMOSIPin); 131 | outMOSI = portOutputRegister(port); 132 | bitMOSI = digitalPinToBitMask(iMOSIPin); 133 | port = digitalPinToPort(iSCKPin); 134 | outSCK = portOutputRegister(port); 135 | bitSCK = digitalPinToBitMask(iSCKPin); 136 | 137 | #endif 138 | 139 | while (iLen) 140 | { 141 | c = *pData++; 142 | iLen--; 143 | if (pOBD->iDCPin == 0xff && pOBD->chip_type != OBD_CHIP_SHARP) // 3-wire SPI, write D/C bit first 144 | { 145 | #ifdef __AVR__ 146 | if (pOBD->mode == MODE_DATA) 147 | *outMOSI |= bitMOSI; 148 | else 149 | *outMOSI &= ~bitMOSI; 150 | *outSCK |= bitSCK; // toggle clock 151 | *outSCK &= ~bitSCK; // no delay needed on SPI devices since AVR is slow 152 | #else 153 | digitalWrite(iMOSIPin, (pOBD->mode == MODE_DATA)); 154 | digitalWrite(iSCKPin, HIGH); 155 | delayMicroseconds(1); 156 | digitalWrite(iSCKPin, LOW); 157 | #endif 158 | } 159 | #ifdef FUTURE 160 | if (c == 0 || c == 0xff) // quicker for all bits equal 161 | { 162 | #ifdef __AVR__ 163 | if (c & 1) 164 | *outMOSI |= bitMOSI; 165 | else 166 | *outMOSI &= ~bitMOSI; 167 | for (i=0; i<8; i++) 168 | { 169 | *outSCK |= bitSCK; 170 | *outSCK &= ~bitSCK; 171 | } 172 | #else 173 | digitalWrite(iMOSIPin, (c & 1)); 174 | for (i=0; i<8; i++) 175 | { 176 | digitalWrite(iSCKPin, HIGH); 177 | delayMicroseconds(1); 178 | digitalWrite(iSCKPin, LOW); 179 | } 180 | #endif 181 | } 182 | else 183 | #endif // FUTURE 184 | { 185 | for (i=0; i<8; i++) 186 | { 187 | #ifdef __AVR__ 188 | if (c & 0x80) // MSB first 189 | *outMOSI |= bitMOSI; 190 | else 191 | *outMOSI &= ~bitMOSI; 192 | *outSCK |= bitSCK; 193 | c <<= 1; 194 | *outSCK &= ~bitSCK; 195 | #else 196 | digitalWrite(iMOSIPin, (c & 0x80) != 0); // MSB first 197 | delayMicroseconds(1); 198 | digitalWrite(iSCKPin, HIGH); 199 | c <<= 1; 200 | delayMicroseconds(1); 201 | digitalWrite(iSCKPin, LOW); 202 | delayMicroseconds(1); 203 | #endif 204 | } 205 | } 206 | } 207 | } /* SPI_BitBang() */ 208 | 209 | // wrapper/adapter functions to make the code work on Linux 210 | #if defined( _LINUX_ ) || defined(ARDUINO_ARCH_MCS51) 211 | static uint8_t pgm_read_byte(const uint8_t *ptr) 212 | { 213 | return *ptr; 214 | } 215 | static int16_t pgm_read_word(const uint8_t *ptr) 216 | { 217 | return ptr[0] + (ptr[1]<<8); 218 | } 219 | #if !defined( MEMORY_ONLY ) && !defined( WIMPY_MCU ) 220 | int I2CReadRegister(BBI2C *pI2C, uint8_t addr, uint8_t reg, uint8_t *pBuf, int iLen) 221 | { 222 | int rc; 223 | rc = write(pI2C->file_i2c, ®, 1); 224 | rc = read(pI2C->file_i2c, pBuf, iLen); 225 | return (rc > 0); 226 | } 227 | int I2CRead(BBI2C *pI2C, uint8_t addr, uint8_t *pBuf, int iLen) 228 | { 229 | int rc; 230 | rc = read(pI2C->file_i2c, pBuf, iLen); 231 | return (rc > 0); 232 | } 233 | void I2CInit(BBI2C *pI2C, uint32_t iSpeed) 234 | { 235 | char filename[32]; 236 | 237 | sprintf(filename, "/dev/i2c-%d", pI2C->iSDA); // I2C bus number passed in SDA pin 238 | if ((pI2C->file_i2c = open(filename, O_RDWR)) < 0) 239 | return;// 1; 240 | if (ioctl(pI2C->file_i2c, I2C_SLAVE, pI2C->iSCL) < 0) // set slave address 241 | { 242 | close(pI2C->file_i2c); 243 | pI2C->file_i2c = 0; 244 | return; // 1; 245 | } 246 | return; // 0; 247 | } 248 | #endif // MEMORY_ONLY 249 | 250 | // Write raw (unfiltered) bytes directly to I2C or SPI 251 | static void RawWrite(OBDISP *pOBD, unsigned char *pData, int iLen) 252 | { 253 | #if !defined( MEMORY_ONLY ) && !defined(WIMPY_MCU) 254 | if (pOBD->com_mode == COM_I2C) {// I2C device 255 | write(pOBD->bbi2c.file_i2c, pData, iLen); 256 | } else { // must be SPI 257 | obdSetDCMode(pOBD, (pData[0] == 0) ? MODE_COMMAND : MODE_DATA); 258 | if (pOBD->iCSPin != 0xff && pOBD->chip_type != OBD_CHIP_SHARP) 259 | digitalWrite(pOBD->iCSPin, LOW); 260 | AIOWriteSPI(pOBD->bbi2c.file_i2c, &pData[1], iLen-1); 261 | if (pOBD->iCSPin != 0xff && pOBD->chip_type != OBD_CHIP_SHARP) 262 | digitalWrite(pOBD->iCSPin, HIGH); 263 | //obdSetDCMode(pOBD, MODE_DATA); 264 | } 265 | #else 266 | (void)pOBD; (void)pData; (void)iLen; 267 | #endif // MEMORY_ONLY 268 | } /* RawWrite() */ 269 | void RawWriteData(OBDISP *pOBD, unsigned char *pData, int iLen) 270 | { 271 | #if !defined( MEMORY_ONLY ) && !defined(WIMPY_MCU) 272 | if (pOBD->com_mode == COM_I2C) {// I2C device 273 | write(pOBD->bbi2c.file_i2c, pData, iLen); 274 | } else { // must be SPI 275 | obdSetDCMode(pOBD, MODE_DATA); 276 | if (pOBD->iFlags & OBD_CS_EVERY_BYTE) { 277 | for (int i=0; iiCSPin, LOW); 279 | AIOWriteSPI(pOBD->bbi2c.file_i2c, &pData[i], 1); 280 | digitalWrite(pOBD->iCSPin, HIGH); 281 | } 282 | } else { 283 | if (pOBD->iCSPin != 0xff && pOBD->chip_type != OBD_CHIP_SHARP) 284 | digitalWrite(pOBD->iCSPin, LOW); 285 | AIOWriteSPI(pOBD->bbi2c.file_i2c, pData, iLen); 286 | if (pOBD->iCSPin != 0xff &&pOBD->chip_type != OBD_CHIP_SHARP) 287 | digitalWrite(pOBD->iCSPin, HIGH); 288 | } 289 | //obdSetDCMode(pOBD, MODE_DATA); 290 | } 291 | #else 292 | (void)pOBD; (void)pData; (void)iLen; 293 | #endif // MEMORY_ONLY 294 | } /* RawWriteData() */ 295 | #else // Arduino 296 | static void RawWrite(OBDISP *pOBD, unsigned char *pData, int iLen) 297 | { 298 | #if !defined( WIMPY_MCU ) 299 | if (pOBD->com_mode == COM_SPI) // we're writing to SPI, treat it differently 300 | { 301 | if (pOBD->iDCPin != 0xff) 302 | { 303 | digitalWrite(pOBD->iDCPin, (pData[0] == 0) ? LOW : HIGH); // data versus command 304 | } 305 | if (pOBD->iCSPin != 0xff && pOBD->chip_type != OBD_CHIP_SHARP) 306 | { 307 | digitalWrite(pOBD->iCSPin, LOW); 308 | } 309 | #ifdef HAL_ESP32_HAL_H_ 310 | { 311 | uint8_t ucTemp[1024]; 312 | if (pOBD->bBitBang) 313 | SPI_BitBang(pOBD, &pData[1], iLen-1, pOBD->iMOSIPin, pOBD->iCLKPin); 314 | else 315 | mySPI->transferBytes(&pData[1], ucTemp, iLen-1); 316 | } 317 | #else 318 | for (int i=1; ibBitBang) 320 | SPI_BitBang(pOBD, &pData[i], 1, pOBD->iMOSIPin, pOBD->iCLKPin); 321 | else 322 | mySPI->transfer(pData[i]); 323 | } 324 | #endif 325 | if (pOBD->iCSPin != 0xff && pOBD->chip_type != OBD_CHIP_SHARP) { 326 | digitalWrite(pOBD->iCSPin, HIGH); 327 | } 328 | if (pOBD->iDCPin != 0xff && pData[0] == 0) { // was command mode, set back to data mode 329 | digitalWrite(pOBD->iDCPin, HIGH); 330 | } 331 | } 332 | else // must be I2C 333 | #endif // !WIMPY_MCU 334 | { 335 | if (pOBD->bbi2c.bWire && iLen > 32) // Hardware I2C has write length limits 336 | { 337 | iLen--; // don't count the 0x40 byte the first time through 338 | while (iLen >= 31) // max 31 data byes + data introducer 339 | { 340 | I2CWrite(&pOBD->bbi2c, pOBD->oled_addr, pData, 32); 341 | iLen -= 31; 342 | pData += 31; 343 | pData[0] = 0x40; 344 | } 345 | if (iLen) iLen++; // If remaining data, add the last 0x40 byte 346 | } 347 | if (iLen) // if any data remaining 348 | { 349 | I2CWrite(&pOBD->bbi2c, pOBD->oled_addr, pData, iLen); 350 | } 351 | } // I2C 352 | } /* RawWrite() */ 353 | void RawWriteData(OBDISP *pOBD, unsigned char *pData, int iLen) 354 | { 355 | #if !defined( WIMPY_MCU ) 356 | if (pOBD->com_mode == COM_SPI) // we're writing to SPI, treat it differently 357 | { 358 | if (pOBD->iDCPin != 0xff) 359 | digitalWrite(pOBD->iDCPin, HIGH); // data mode 360 | if (pOBD->iCSPin != 0xff && pOBD->chip_type != OBD_CHIP_SHARP) 361 | digitalWrite(pOBD->iCSPin, LOW); 362 | //#ifdef HAL_ESP32_HAL_H_ 363 | // { 364 | // uint8_t ucTemp[1024]; 365 | // mySPI->transferBytes(pData, ucTemp, iLen); 366 | // } 367 | //#else 368 | if (pOBD->iFlags & OBD_CS_EVERY_BYTE) { 369 | for (int i=0; iiCSPin, LOW); 371 | mySPI->transfer(pData[i]); 372 | digitalWrite(pOBD->iCSPin, HIGH); 373 | } 374 | } else { // no need for CS on every byte 375 | for (int i=0; itransfer(pData[i]); 377 | } 378 | } 379 | //#endif 380 | if (pOBD->iCSPin != 0xff && pOBD->chip_type != OBD_CHIP_SHARP) 381 | digitalWrite(pOBD->iCSPin, HIGH); 382 | } 383 | else // must be I2C 384 | #endif // !WIMPY_MCU 385 | { 386 | u8Temp[0] = 0x40; // data prefix byte 387 | while (iLen >= 31) { // max 31 data byes + data introducer 388 | memcpy(&u8Temp[1], pData, 31); 389 | I2CWrite(&pOBD->bbi2c, pOBD->oled_addr, u8Temp, 32); 390 | iLen -= 31; 391 | pData += 31; 392 | } // while >= 31 bytes to send 393 | if (iLen) // if any data remaining 394 | { 395 | memcpy(&u8Temp[1], pData, iLen); 396 | I2CWrite(&pOBD->bbi2c, pOBD->oled_addr, u8Temp, iLen+1); 397 | } 398 | } // I2C 399 | } /* RawWriteData() */ 400 | #endif // _LINUX_ 401 | 402 | #ifdef _LINUX_ 403 | void _delay(int iDelay) 404 | { 405 | usleep(iDelay * 1000); 406 | } /* _delay() */ 407 | #else // Arduino 408 | void _delay(int iDelay) 409 | { 410 | #ifdef NOT_HAL_ESP32_HAL_H_ 411 | // light sleep to save power 412 | esp_sleep_enable_timer_wakeup(iDelay * 1000); 413 | // esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); 414 | esp_light_sleep_start(); 415 | #else // any other platform 416 | delay(iDelay); // use the Arduino delay function 417 | #endif // ESP32 418 | } 419 | #endif // _LINUX_ 420 | -------------------------------------------------------------------------------- /src/obd_stub.inl: -------------------------------------------------------------------------------- 1 | // 2 | // Stub functions to allow the obd_gfx functions to be used 3 | // in a stand-alone mode without the display interface code 4 | // 5 | // obd_stub.inl 6 | #include 7 | #define MAX_CACHE 192 8 | static uint8_t u8Cache[MAX_CACHE]; 9 | static volatile uint8_t u8End = 0; 10 | static uint8_t u8Temp[40]; // for stretched character drawing 11 | 12 | const uint8_t ucMirror[256] PROGMEM = 13 | {0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, 14 | 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, 15 | 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, 16 | 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, 17 | 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, 18 | 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, 19 | 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, 20 | 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, 21 | 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, 22 | 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, 23 | 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, 24 | 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, 25 | 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, 26 | 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, 27 | 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, 28 | 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255}; 29 | 30 | uint8_t pgm_read_byte(const uint8_t *p) 31 | { 32 | return p[0]; 33 | } /* pgm_read_byte() */ 34 | 35 | // Write raw (unfiltered) bytes directly to I2C or SPI 36 | static void RawWrite(OBDISP *pOBD, unsigned char *pData, int iLen) 37 | { 38 | (void)pOBD; (void)pData; (void)iLen; 39 | } /* RawWrite() */ 40 | 41 | void obdSetPosition(OBDISP *pOBD, int x, int y, int bRender) 42 | { 43 | int iPitch = pOBD->width; 44 | 45 | y >>= 3; // DEBUG - since we address the display by lines of 8 pixels 46 | pOBD->iScreenOffset = (y*iPitch)+x; 47 | 48 | } /* obdSetPosition() */ 49 | 50 | void obdWriteDataBlock(OBDISP *pOBD, unsigned char *ucBuf, int iLen, int bRender) 51 | { 52 | int iPitch, iBufferSize; 53 | int iRedOffset = 0; 54 | 55 | iPitch = pOBD->width; 56 | iBufferSize = iPitch * ((pOBD->height+7) / 8); 57 | if (pOBD->iFG == OBD_RED) { 58 | iRedOffset = pOBD->width * ((pOBD->height+7)/8); 59 | } 60 | // Keep a copy in local buffer 61 | if (pOBD->ucScreen && (iLen + pOBD->iScreenOffset) <= iBufferSize) 62 | { 63 | memcpy(&pOBD->ucScreen[iRedOffset + pOBD->iScreenOffset], ucBuf, iLen); 64 | pOBD->iScreenOffset += iLen; 65 | // wrap around ? 66 | if (pOBD->iScreenOffset >= iBufferSize) 67 | pOBD->iScreenOffset -= iBufferSize; 68 | } 69 | } /* obdWriteDataBlock() */ 70 | 71 | --------------------------------------------------------------------------------