SSD1306 OLED display driver 1.7.8 This library is developed to control SSD1306/SSD1331/SSD1351/IL9163/PCD8554 RGB i2c/spi LED displays

ssd1306_generic.c
1 /*
2 MIT License
3
4 Copyright (c) 2016-2018, Alexey Dynda
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23 */
24
28
29 #include "ssd1306.h"
30 #include "ssd1306_fonts.h"
31 #include "lcd/lcd_common.h"
32 #include "intf/i2c/ssd1306_i2c.h"
33 #include "intf/spi/ssd1306_spi.h"
34 #include "intf/ssd1306_interface.h"
35 #include "ssd1306_hal/io.h"
36 #include "nano_gfx_types.h"
37
38 enum
39 {
40 SSD1306_OLD_FIXED_FORMAT = 0x00,
41 SSD1306_NEW_FIXED_FORMAT = 0x01,
42 SSD1306_NEW_FORMAT = 0x02,
43 SSD1306_SQUIX_FORMAT = 0x03,
44 };
45
46 uint16_t ssd1306_color = 0xFFFF;
47 lcduint_t ssd1306_cursorX = 0;
48 lcduint_t ssd1306_cursorY = 0;
49 SFixedFontInfo s_fixedFont = { {0} };
50 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
51 uint8_t g_ssd1306_unicode = 1;
52 #endif
53 static void (*s_ssd1306_getCharBitmap)(uint16_t unicode, SCharInfo *info) = NULL;
54
55 static const uint8_t *ssd1306_getCharGlyph(char ch);
56 static const uint8_t *ssd1306_getU16CharGlyph(uint16_t unicode);
57
58 uint8_t ssd1306_displayHeight()
59 {
60 return ssd1306_lcd.height;
61 }
62
63 uint8_t ssd1306_displayWidth()
64 {
65 return ssd1306_lcd.width;
66 }
67
68 void ssd1306_setCursor(lcdint_t x, lcdint_t y)
69 {
70 ssd1306_cursorX = x;
71 ssd1306_cursorY = y;
72 }
73
74 static const uint8_t * ssd1306_readUnicodeRecord(SUnicodeBlockRecord *r, const uint8_t *p)
75 {
76 r->start_code =( pgm_read_byte(&p[0]) << 8) | (pgm_read_byte(&p[1]));
77 r->count = pgm_read_byte(&p[2]);
78 return (r->count > 0) ? (&p[3]): NULL;
79 }
80
81
82 void ssd1306_setSecondaryFont(const uint8_t * progmemUnicode)
83 {
84 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
85 s_fixedFont.secondary_table = progmemUnicode;
86 if (s_fixedFont.secondary_table != NULL)
87 {
88 s_fixedFont.secondary_table += sizeof(SFontHeaderRecord);
89 }
90 #endif
91 }
92
93 void ssd1306_getCharBitmap(uint16_t unicode, SCharInfo *info)
94 {
95 return s_ssd1306_getCharBitmap( unicode, info );
96 }
97
98 uint16_t ssd1306_unicode16FromUtf8(uint8_t ch)
99 {
100 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
101 static uint16_t unicode = 0;
102 ch &= 0x000000FF;
103 if (!unicode)
104 {
105 if ( ch >= 0xc0 )
106 {
107 unicode = ch;
108 return SSD1306_MORE_CHARS_REQUIRED;
109 }
110 return ch;
111 }
112 uint16_t code = ((unicode & 0x1f) << 6) | (ch & 0x3f);
113 unicode = 0;
114 return code;
115 #else
116 return ch;
117 #endif
118 }
119
120 void ssd1306_enableUtf8Mode(void)
121 {
122 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
123 g_ssd1306_unicode = 1;
124 #endif
125 }
126
127 void ssd1306_enableAsciiMode(void)
128 {
129 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
130 g_ssd1306_unicode = 0;
131 #endif
132 }
133
137
141
142 static const uint8_t *ssd1306_getCharGlyph(char ch)
143 {
144 return &s_fixedFont.primary_table[ (ch - s_fixedFont.h.ascii_offset) *
145 s_fixedFont.glyph_size +
146 (s_fixedFont.h.type == 0x01 ? sizeof(SUnicodeBlockRecord) : 0) ];
147 }
148
149 static const uint8_t *ssd1306_searchCharGlyph(const uint8_t * unicode_table, uint16_t unicode)
150 {
151 SUnicodeBlockRecord r;
152 const uint8_t *data = unicode_table;
153 // looking for required unicode table
154 while (1)
155 {
156 ssd1306_readUnicodeRecord( &r, data );
157 if (r.count == 0)
158 {
159 break;
160 }
161 data += sizeof(SUnicodeBlockRecord);
162 if ( ( unicode >= r.start_code) && ( unicode < (r.start_code + r.count) ) )
163 {
164 break;
165 }
166 data += r.count * s_fixedFont.glyph_size;
167 }
168 if (r.count == 0)
169 {
170 // Sorry, no glyph found for the specified character
171 return unicode_table;
172 }
173 return &data[ (unicode - r.start_code) * s_fixedFont.glyph_size ];
174 }
175
176 static const uint8_t *ssd1306_getU16CharGlyph(uint16_t unicode)
177 {
178 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
179 const uint8_t * glyph = NULL;
180 if (g_ssd1306_unicode)
181 {
182 if ((unicode < 128) && (s_fixedFont.h.type == 0x00) && (s_fixedFont.primary_table != NULL))
183 {
184 return ssd1306_getCharGlyph(unicode);
185 }
186 if (s_fixedFont.primary_table)
187 {
188 glyph = ssd1306_searchCharGlyph( s_fixedFont.primary_table, unicode );
189 }
190 if (!glyph && s_fixedFont.secondary_table)
191 {
192 glyph = ssd1306_searchCharGlyph( s_fixedFont.secondary_table, unicode );
193 }
194 if (!glyph)
195 {
196 return ssd1306_getCharGlyph( s_fixedFont.h.ascii_offset );
197 }
198 return glyph;
199 }
200 else
201 #endif
202 {
203 return ssd1306_getCharGlyph(unicode);
204 }
205 }
206
207 static void __ssd1306_oldFormatGetBitmap(uint16_t unicode, SCharInfo *info)
208 {
209 if (info)
210 {
211 info->width = s_fixedFont.h.width;
212 info->height = s_fixedFont.h.height;
213 info->spacing = 0;
214 info->glyph = ssd1306_getU16CharGlyph( unicode );
215 }
216 }
217
218 void ssd1306_setFixedFont(const uint8_t * progmemFont)
219 {
220 s_fixedFont.h.type = pgm_read_byte( &progmemFont[0] );
221 s_fixedFont.h.width = pgm_read_byte(&progmemFont[1]);
222 s_fixedFont.h.height = pgm_read_byte(&progmemFont[2]);
223 s_fixedFont.h.ascii_offset = pgm_read_byte(&progmemFont[3]);
224 s_fixedFont.primary_table = progmemFont + 4;
225 s_ssd1306_getCharBitmap = __ssd1306_oldFormatGetBitmap;
226 s_fixedFont.pages = (s_fixedFont.h.height + 7) >> 3;
227 s_fixedFont.glyph_size = s_fixedFont.pages * s_fixedFont.h.width;
228 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
229 s_fixedFont.secondary_table = NULL;
230 #endif
231 }
232
236
237 static void __ssd1306_newFormatGetBitmap(uint16_t unicode, SCharInfo *info)
238 {
239 if (info)
240 {
241 uint8_t table_index = 0;
242 const uint8_t *data = s_fixedFont.primary_table;
243 while (data)
244 {
245 SUnicodeBlockRecord r;
246 data = ssd1306_readUnicodeRecord( &r, data );
247 if (!data)
248 {
249 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
250 if ( table_index == 0 )
251 {
252 table_index++;
253 data = s_fixedFont.secondary_table;
254 continue;
255 }
256 #endif
257 break;
258 }
259 /* Check that unicode in the section being processed */
260 if ( ( unicode < r.start_code) || ( unicode >= (r.start_code + r.count) ) )
261 {
262 // skip jump table
263 data += r.count * 4;
264 // skip block bitmap data
265 data += ((pgm_read_byte(&data[0]) << 8) | (pgm_read_byte(&data[1]))) + 2;
266 continue;
267 }
268 /* At this point data points to jump table (offset|offset|bytes|width) */
269 unicode -= r.start_code;
270 data += unicode * 4;
271 uint16_t offset = (pgm_read_byte(&data[0]) << 8) | (pgm_read_byte(&data[1]));
272 uint8_t glyph_width = pgm_read_byte(&data[2]);
273 uint8_t glyph_height = pgm_read_byte(&data[3]);
274 info->width = glyph_width;
275 info->height = glyph_height;
276 info->spacing = glyph_width ? 1 : (s_fixedFont.h.width >> 1);
277 info->glyph = data + (r.count - unicode) * 4 + 2 + offset;
278 break;
279 }
280 if (!info->glyph)
281 {
282 info->width = 0;
283 info->height = 0;
284 info->spacing = s_fixedFont.h.width >> 1;
285 info->glyph = s_fixedFont.primary_table;
286 }
287 }
288 }
289
290 void ssd1306_setFreeFont(const uint8_t * progmemFont)
291 {
292 s_fixedFont.h.type = pgm_read_byte( &progmemFont[0] );
293 s_fixedFont.h.width = pgm_read_byte(&progmemFont[1]);
294 s_fixedFont.h.height = pgm_read_byte(&progmemFont[2]);
295 s_fixedFont.h.ascii_offset = pgm_read_byte(&progmemFont[3]);
296 s_fixedFont.primary_table = progmemFont + 4;
297 s_ssd1306_getCharBitmap = __ssd1306_newFormatGetBitmap;
298 s_fixedFont.pages = (s_fixedFont.h.height + 7) >> 3;
299 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
300 s_fixedFont.secondary_table = NULL;
301 #endif
302 }
303
307
308 static void __ssd1306_squixFormatGetBitmap(uint16_t unicode, SCharInfo *info)
309 {
310 if (info)
311 {
312 const uint8_t *data = s_fixedFont.primary_table;
313 /* Check that unicode in the section being processed */
314 if ( !data || ( unicode < s_fixedFont.h.ascii_offset) || ( unicode >= (s_fixedFont.h.ascii_offset + s_fixedFont.count) ) )
315 {
316 info->width = 0;
317 info->height = 0;
318 info->spacing = s_fixedFont.h.width >> 1;
319 info->glyph = s_fixedFont.primary_table;
320 return;
321 }
322 /* At this point data points to jump table (offset|offset|bytes|width) */
323 const uint8_t * bitmap_data = data + (uint16_t)s_fixedFont.count * 4;
324 unicode -= s_fixedFont.h.ascii_offset;
325 data += (unicode * 4);
326 uint16_t offset = (pgm_read_byte(&data[0]) << 8) | pgm_read_byte(&data[1]);
327 uint8_t glyph_bytes = pgm_read_byte(&data[2]);
328 // uint8_t width = pgm_read_byte(&data[3]);
329 info->width = glyph_bytes; //(glyph_bytes + s_fixedFont.pages - 1) / s_fixedFont.pages;
330 info->height = s_fixedFont.h.height / 2;
331 info->spacing = 1;
332 // uint8_t index=0;
333 info->glyph = bitmap_data;
334 if ( offset != 0xFFFF )
335 {
336 info->glyph += offset;
337 }
338 }
339 }
340
341 void ssd1306_setSquixFont(const uint8_t * progmemFont)
342 {
343 s_fixedFont.h.type = SSD1306_SQUIX_FORMAT;
344 s_fixedFont.h.width = pgm_read_byte(&progmemFont[0]);
345 s_fixedFont.h.height = pgm_read_byte(&progmemFont[1]);
346 s_fixedFont.h.ascii_offset = pgm_read_byte(&progmemFont[2]);
347 s_fixedFont.count = pgm_read_byte(&progmemFont[3]);
348 s_fixedFont.primary_table = progmemFont + 4;
349 s_ssd1306_getCharBitmap = __ssd1306_squixFormatGetBitmap;
350 s_fixedFont.pages = (s_fixedFont.h.height + 7) >> 3;
351 s_fixedFont.glyph_size = s_fixedFont.pages * s_fixedFont.h.width;
352 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
353 s_fixedFont.secondary_table = NULL;
354 #endif
355 }
ssd1306_setCursor
void ssd1306_setCursor(lcdint_t x, lcdint_t y)
Sets cursor position for text mode print functions.
Definition: ssd1306_generic.c:68
SCharInfo::height
uint8_t height
char height in pixels
Definition: nano_gfx_types.h:110
lcd_common.h
SFixedFontInfo::primary_table
const uint8_t * primary_table
font chars bits
Definition: nano_gfx_types.h:100
SCharInfo
Definition: nano_gfx_types.h:107
ssd1306.h
SUnicodeBlockRecord::start_code
uint16_t start_code
unicode start code
Definition: nano_gfx_types.h:87
ssd1306_enableAsciiMode
void ssd1306_enableAsciiMode(void)
Definition: ssd1306_generic.c:127
SFontHeaderRecord::width
uint8_t width
width in pixels
Definition: nano_gfx_types.h:79
ssd1306_getCharBitmap
void ssd1306_getCharBitmap(uint16_t unicode, SCharInfo *info)
returns char data for currently set (active) font.
Definition: ssd1306_generic.c:93
io.h
ssd1306_i2c.h
SFontHeaderRecord::type
uint8_t type
font type: 0 - Fixed Font
Definition: nano_gfx_types.h:78
SFontHeaderRecord::height
uint8_t height
height in pixels
Definition: nano_gfx_types.h:80
ssd1306_displayWidth
uint8_t ssd1306_displayWidth()
Definition: ssd1306_generic.c:63
SFixedFontInfo
Definition: nano_gfx_types.h:94
SUnicodeBlockRecord
Definition: nano_gfx_types.h:85
SFontHeaderRecord::ascii_offset
uint8_t ascii_offset
ascii offset
Definition: nano_gfx_types.h:81
ssd1306_spi.h
ssd1306_lcd
ssd1306_lcd_t ssd1306_lcd
Definition: lcd_common.c:32
ssd1306_setFixedFont
void ssd1306_setFixedFont(const uint8_t *progmemFont)
Definition: ssd1306_generic.c:218
ssd1306_setFreeFont
void ssd1306_setFreeFont(const uint8_t *progmemFont)
Definition: ssd1306_generic.c:290
nano_gfx_types.h
SUnicodeBlockRecord::count
uint8_t count
count of unicode chars in block
Definition: nano_gfx_types.h:88
ssd1306_enableUtf8Mode
void ssd1306_enableUtf8Mode(void)
Definition: ssd1306_generic.c:120
ssd1306_lcd_t::height
lcduint_t height
Definition: lcd_common.h:97
SCharInfo::width
uint8_t width
char width in pixels
Definition: nano_gfx_types.h:109
SFixedFontInfo::secondary_table
const uint8_t * secondary_table
font chars bits
Definition: nano_gfx_types.h:102
s_fixedFont
SFixedFontInfo s_fixedFont
Definition: ssd1306_generic.c:49
SFixedFontInfo::h
SFontHeaderRecord h
record, containing information on font
Definition: nano_gfx_types.h:96
ssd1306_interface.h
ssd1306_setSecondaryFont
void ssd1306_setSecondaryFont(const uint8_t *progmemUnicode)
Definition: ssd1306_generic.c:82
ssd1306_fonts.h
SCharInfo::glyph
const uint8_t * glyph
char data, located in progmem.
Definition: nano_gfx_types.h:112
SFontHeaderRecord
Definition: nano_gfx_types.h:76
SSD1306_MORE_CHARS_REQUIRED
#define SSD1306_MORE_CHARS_REQUIRED
Definition: ssd1306_fonts.h:44
SCharInfo::spacing
uint8_t spacing
additional spaces after char in pixels
Definition: nano_gfx_types.h:111
ssd1306_displayHeight
uint8_t ssd1306_displayHeight()
Definition: ssd1306_generic.c:58
ssd1306_lcd_t::width
lcduint_t width
Definition: lcd_common.h:94
SFixedFontInfo::glyph_size
uint8_t glyph_size
glyph size in bytes
Definition: nano_gfx_types.h:99
SFixedFontInfo::pages
uint8_t pages
height in pages (each page height is 8-pixels)
Definition: nano_gfx_types.h:98
SFixedFontInfo::count
uint8_t count
count of characters
Definition: nano_gfx_types.h:97