SSD1306 OLED display driver 1.8.2 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-2019, 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 }, 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 lcduint_t ssd1306_displayHeight()
59 {
60 return ssd1306_lcd.height;
61 }
62
63 lcduint_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 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
150 static const uint8_t *ssd1306_searchCharGlyph(const uint8_t * unicode_table, uint16_t unicode)
151 {
152 SUnicodeBlockRecord r;
153 const uint8_t *data = unicode_table;
154 // looking for required unicode table
155 while (1)
156 {
157 ssd1306_readUnicodeRecord( &r, data );
158 if (r.count == 0)
159 {
160 break;
161 }
162 data += sizeof(SUnicodeBlockRecord);
163 if ( ( unicode >= r.start_code) && ( unicode < (r.start_code + r.count) ) )
164 {
165 break;
166 }
167 data += r.count * s_fixedFont.glyph_size;
168 }
169 if (r.count == 0)
170 {
171 // Sorry, no glyph found for the specified character
172 return NULL;
173 }
174 return &data[ (unicode - r.start_code) * s_fixedFont.glyph_size ];
175 }
176 #endif
177
178 static const uint8_t *ssd1306_getU16CharGlyph(uint16_t unicode)
179 {
180 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
181 const uint8_t * glyph = NULL;
182 if (g_ssd1306_unicode)
183 {
184 if ((unicode < 128) && (s_fixedFont.h.type == 0x00) && (s_fixedFont.primary_table != NULL))
185 {
186 return ssd1306_getCharGlyph(unicode);
187 }
188 if (s_fixedFont.primary_table)
189 {
190 glyph = ssd1306_searchCharGlyph( s_fixedFont.primary_table, unicode );
191 }
192 if (!glyph && s_fixedFont.secondary_table)
193 {
194 glyph = ssd1306_searchCharGlyph( s_fixedFont.secondary_table, unicode );
195 }
196 if (!glyph)
197 {
198 return ssd1306_getCharGlyph( s_fixedFont.h.ascii_offset );
199 }
200 return glyph;
201 }
202 else
203 #endif
204 {
205 return ssd1306_getCharGlyph(unicode);
206 }
207 }
208
209 static void __ssd1306_oldFormatGetBitmap(uint16_t unicode, SCharInfo *info)
210 {
211 if (info)
212 {
213 info->width = s_fixedFont.h.width;
214 info->height = s_fixedFont.h.height;
215 info->spacing = 0;
216 info->glyph = ssd1306_getU16CharGlyph( unicode );
217 }
218 }
219
220 void ssd1306_setFixedFont(const uint8_t * progmemFont)
221 {
222 s_fixedFont.h.type = pgm_read_byte( &progmemFont[0] );
223 s_fixedFont.h.width = pgm_read_byte(&progmemFont[1]);
224 s_fixedFont.h.height = pgm_read_byte(&progmemFont[2]);
225 s_fixedFont.h.ascii_offset = pgm_read_byte(&progmemFont[3]);
226 s_fixedFont.primary_table = progmemFont + 4;
227 s_ssd1306_getCharBitmap = __ssd1306_oldFormatGetBitmap;
228 s_fixedFont.pages = (s_fixedFont.h.height + 7) >> 3;
229 s_fixedFont.glyph_size = s_fixedFont.pages * s_fixedFont.h.width;
230 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
231 s_fixedFont.secondary_table = NULL;
232 #endif
233 }
234
235 void ssd1306_setFixedFont_oldStyle(const uint8_t * progmemFont)
236 {
237 s_fixedFont.h.type = pgm_read_byte( &progmemFont[0] );
238 s_fixedFont.h.width = pgm_read_byte(&progmemFont[1]);
239 s_fixedFont.h.height = pgm_read_byte(&progmemFont[2]);
240 s_fixedFont.h.ascii_offset = pgm_read_byte(&progmemFont[3]);
241 s_fixedFont.primary_table = progmemFont + 4;
242 s_fixedFont.pages = (s_fixedFont.h.height + 7) >> 3;
243 s_fixedFont.glyph_size = s_fixedFont.pages * s_fixedFont.h.width;
244 }
245
249
250 static void __ssd1306_newFormatGetBitmap(uint16_t unicode, SCharInfo *info)
251 {
252 if (info)
253 {
254 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
255 uint8_t table_index = 0;
256 #endif
257 const uint8_t *data = s_fixedFont.primary_table;
258 while (data)
259 {
260 SUnicodeBlockRecord r;
261 data = ssd1306_readUnicodeRecord( &r, data );
262 if (!data)
263 {
264 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
265 if ( table_index == 0 )
266 {
267 table_index++;
268 data = s_fixedFont.secondary_table;
269 continue;
270 }
271 #endif
272 break;
273 }
274 /* Check that unicode in the section being processed */
275 if ( ( unicode < r.start_code) || ( unicode >= (r.start_code + r.count) ) )
276 {
277 // skip jump table
278 data += r.count * 4;
279 // skip block bitmap data
280 data += ((pgm_read_byte(&data[0]) << 8) | (pgm_read_byte(&data[1]))) + 2;
281 continue;
282 }
283 /* At this point data points to jump table (offset|offset|bytes|width) */
284 unicode -= r.start_code;
285 data += unicode * 4;
286 uint16_t offset = (pgm_read_byte(&data[0]) << 8) | (pgm_read_byte(&data[1]));
287 uint8_t glyph_width = pgm_read_byte(&data[2]);
288 uint8_t glyph_height = pgm_read_byte(&data[3]);
289 info->width = glyph_width;
290 info->height = glyph_height;
291 info->spacing = glyph_width ? 1 : (s_fixedFont.h.width >> 1);
292 info->glyph = data + (r.count - unicode) * 4 + 2 + offset;
293 break;
294 }
295 if (!info->glyph)
296 {
297 info->width = 0;
298 info->height = 0;
299 info->spacing = s_fixedFont.h.width >> 1;
300 info->glyph = s_fixedFont.primary_table;
301 }
302 }
303 }
304
305 void ssd1306_setFreeFont(const uint8_t * progmemFont)
306 {
307 s_fixedFont.h.type = pgm_read_byte( &progmemFont[0] );
308 s_fixedFont.h.width = pgm_read_byte(&progmemFont[1]);
309 s_fixedFont.h.height = pgm_read_byte(&progmemFont[2]);
310 s_fixedFont.h.ascii_offset = pgm_read_byte(&progmemFont[3]);
311 s_fixedFont.primary_table = progmemFont + 4;
312 s_ssd1306_getCharBitmap = __ssd1306_newFormatGetBitmap;
313 s_fixedFont.pages = (s_fixedFont.h.height + 7) >> 3;
314 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
315 s_fixedFont.secondary_table = NULL;
316 #endif
317 }
318
322
323 static void __ssd1306_squixFormatGetBitmap(uint16_t unicode, SCharInfo *info)
324 {
325 if (info)
326 {
327 const uint8_t *data = s_fixedFont.primary_table;
328 /* Check that unicode in the section being processed */
329 if ( !data || ( unicode < s_fixedFont.h.ascii_offset) || ( unicode >= (s_fixedFont.h.ascii_offset + s_fixedFont.count) ) )
330 {
331 info->width = 0;
332 info->height = 0;
333 info->spacing = s_fixedFont.h.width >> 1;
334 info->glyph = s_fixedFont.primary_table;
335 return;
336 }
337 /* At this point data points to jump table (offset|offset|bytes|width) */
338 const uint8_t * bitmap_data = data + (uint16_t)s_fixedFont.count * 4;
339 unicode -= s_fixedFont.h.ascii_offset;
340 data += (unicode * 4);
341 uint16_t offset = (pgm_read_byte(&data[0]) << 8) | pgm_read_byte(&data[1]);
342 uint8_t glyph_bytes = pgm_read_byte(&data[2]);
343 // uint8_t width = pgm_read_byte(&data[3]);
344 info->width = glyph_bytes; //(glyph_bytes + s_fixedFont.pages - 1) / s_fixedFont.pages;
345 info->height = s_fixedFont.h.height / 2;
346 info->spacing = 1;
347 // uint8_t index=0;
348 info->glyph = bitmap_data;
349 if ( offset != 0xFFFF )
350 {
351 info->glyph += offset;
352 }
353 }
354 }
355
356 void ssd1306_setSquixFont(const uint8_t * progmemFont)
357 {
358 s_fixedFont.h.type = SSD1306_SQUIX_FORMAT;
359 s_fixedFont.h.width = pgm_read_byte(&progmemFont[0]);
360 s_fixedFont.h.height = pgm_read_byte(&progmemFont[1]);
361 s_fixedFont.h.ascii_offset = pgm_read_byte(&progmemFont[2]);
362 s_fixedFont.count = pgm_read_byte(&progmemFont[3]);
363 s_fixedFont.primary_table = progmemFont + 4;
364 s_ssd1306_getCharBitmap = __ssd1306_squixFormatGetBitmap;
365 s_fixedFont.pages = (s_fixedFont.h.height + 7) >> 3;
366 s_fixedFont.glyph_size = s_fixedFont.pages * s_fixedFont.h.width;
367 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
368 s_fixedFont.secondary_table = NULL;
369 #endif
370 }
371
372 lcduint_t ssd1306_getTextSize(const char *text, lcduint_t *height)
373 {
374 lcduint_t width = 0;
375 while (*text)
376 {
377 if (*text == '\r' || *text == '\n')
378 {
379 text++;
380 break;
381 }
382 uint16_t unicode = ssd1306_unicode16FromUtf8(*text);
383 if (unicode == SSD1306_MORE_CHARS_REQUIRED)
384 {
385 text++;
386 continue;
387 }
388 SCharInfo char_info;
389 ssd1306_getCharBitmap(unicode, &char_info);
390 width += char_info.width + char_info.spacing;
391 if ( height ) *height = char_info.height;
392 text++;
393 }
394 return width;
395 }
ssd1306_setSecondaryFont
void ssd1306_setSecondaryFont(const uint8_t *progmemUnicode)
Definition: ssd1306_generic.c:82
ssd1306_displayWidth
lcduint_t ssd1306_displayWidth()
Definition: ssd1306_generic.c:63
SCharInfo::height
uint8_t height
char height in pixels
Definition: nano_gfx_types.h:121
lcd_common.h
SFixedFontInfo::primary_table
const uint8_t * primary_table
font chars bits
Definition: nano_gfx_types.h:111
SCharInfo
Definition: nano_gfx_types.h:118
ssd1306.h
SUnicodeBlockRecord::start_code
uint16_t start_code
unicode start code
Definition: nano_gfx_types.h:98
SFontHeaderRecord::width
uint8_t width
width in pixels
Definition: nano_gfx_types.h:90
io.h
ssd1306_i2c.h
SFontHeaderRecord::type
uint8_t type
font type: 0 - Fixed Font
Definition: nano_gfx_types.h:89
ssd1306_setFixedFont
void ssd1306_setFixedFont(const uint8_t *progmemFont)
Definition: ssd1306_generic.c:220
SFontHeaderRecord::height
uint8_t height
height in pixels
Definition: nano_gfx_types.h:91
SFixedFontInfo
Definition: nano_gfx_types.h:105
SUnicodeBlockRecord
Definition: nano_gfx_types.h:96
SFontHeaderRecord::ascii_offset
uint8_t ascii_offset
ascii offset
Definition: nano_gfx_types.h:92
ssd1306_spi.h
ssd1306_setFreeFont
void ssd1306_setFreeFont(const uint8_t *progmemFont)
Definition: ssd1306_generic.c:305
ssd1306_lcd
ssd1306_lcd_t ssd1306_lcd
Definition: lcd_common.c:33
ssd1306_enableAsciiMode
void ssd1306_enableAsciiMode(void)
Definition: ssd1306_generic.c:127
nano_gfx_types.h
SUnicodeBlockRecord::count
uint8_t count
count of unicode chars in block
Definition: nano_gfx_types.h:99
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:120
SFixedFontInfo::secondary_table
const uint8_t * secondary_table
font chars bits
Definition: nano_gfx_types.h:113
ssd1306_setCursor
void ssd1306_setCursor(lcdint_t x, lcdint_t y)
Sets cursor position for text mode print functions.
Definition: ssd1306_generic.c:68
s_fixedFont
SFixedFontInfo s_fixedFont
Definition: ssd1306_generic.c:49
SFixedFontInfo::h
SFontHeaderRecord h
record, containing information on font
Definition: nano_gfx_types.h:107
ssd1306_interface.h
ssd1306_fonts.h
ssd1306_getTextSize
lcduint_t ssd1306_getTextSize(const char *text, lcduint_t *height)
Definition: ssd1306_generic.c:372
SCharInfo::glyph
const uint8_t * glyph
char data, located in progmem.
Definition: nano_gfx_types.h:123
SFontHeaderRecord
Definition: nano_gfx_types.h:87
ssd1306_displayHeight
lcduint_t ssd1306_displayHeight()
Definition: ssd1306_generic.c:58
SCharInfo::spacing
uint8_t spacing
additional spaces after char in pixels
Definition: nano_gfx_types.h:122
ssd1306_getCharBitmap
void ssd1306_getCharBitmap(uint16_t unicode, SCharInfo *info)
returns char data for currently set (active) font.
Definition: ssd1306_generic.c:93
ssd1306_lcd_t::width
lcduint_t width
Definition: lcd_common.h:94
SSD1306_MORE_CHARS_REQUIRED
#define SSD1306_MORE_CHARS_REQUIRED
Definition: ssd1306_generic.h:43
SFixedFontInfo::glyph_size
uint8_t glyph_size
glyph size in bytes
Definition: nano_gfx_types.h:110
SFixedFontInfo::pages
uint8_t pages
height in pages (each page height is 8-pixels)
Definition: nano_gfx_types.h:109
SFixedFontInfo::count
uint8_t count
count of characters
Definition: nano_gfx_types.h:108
ssd1306_enableUtf8Mode
void ssd1306_enableUtf8Mode(void)
Definition: ssd1306_generic.c:120