SSD1306 OLED display driver  1.7.12
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;
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 
59 {
60  return ssd1306_lcd.height;
61 }
62 
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;
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 
121 {
122 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
123  g_ssd1306_unicode = 1;
124 #endif
125 }
126 
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 {
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 NULL;
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  {
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 }
lcduint_t ssd1306_displayWidth()
void ssd1306_setCursor(lcdint_t x, lcdint_t y)
Sets cursor position for text mode print functions.
uint8_t height
char height in pixels
const uint8_t * primary_table
font chars bits
uint16_t start_code
unicode start code
void ssd1306_enableAsciiMode(void)
uint8_t width
width in pixels
void ssd1306_getCharBitmap(uint16_t unicode, SCharInfo *info)
returns char data for currently set (active) font.
uint8_t type
font type: 0 - Fixed Font
uint8_t height
height in pixels
uint8_t ascii_offset
ascii offset
ssd1306_lcd_t ssd1306_lcd
Definition: lcd_common.c:32
void ssd1306_setFixedFont(const uint8_t *progmemFont)
void ssd1306_setFreeFont(const uint8_t *progmemFont)
uint8_t count
count of unicode chars in block
void ssd1306_enableUtf8Mode(void)
lcduint_t height
Definition: lcd_common.h:97
uint8_t width
char width in pixels
const uint8_t * secondary_table
font chars bits
SFixedFontInfo s_fixedFont
SFontHeaderRecord h
record, containing information on font
void ssd1306_setSecondaryFont(const uint8_t *progmemUnicode)
const uint8_t * glyph
char data, located in progmem.
#define SSD1306_MORE_CHARS_REQUIRED
Definition: ssd1306_fonts.h:44
lcduint_t ssd1306_displayHeight()
uint8_t spacing
additional spaces after char in pixels
lcduint_t width
Definition: lcd_common.h:94
uint8_t glyph_size
glyph size in bytes
uint8_t pages
height in pages (each page height is 8-pixels)
uint8_t count
count of characters