Fixes and testing, all should work now
This commit is contained in:
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include "cgram.h"
|
#include "cgram.h"
|
||||||
|
|
||||||
const struct cgram_pattern CGRAM_CZ[] = {
|
const struct LcdBuf_CGRAM_Symbol CGRAM_CZ[] = {
|
||||||
{
|
{
|
||||||
.symbol = "ě",
|
.symbol = "ě",
|
||||||
.fallback = 'e',
|
.fallback = 'e',
|
||||||
|
|||||||
+2
-2
@@ -9,7 +9,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/** Pattern for CGRAM */
|
/** Pattern for CGRAM */
|
||||||
struct cgram_pattern {
|
struct LcdBuf_CGRAM_Symbol {
|
||||||
/** The symbol displayed */
|
/** The symbol displayed */
|
||||||
struct Utf8Char symbol;
|
struct Utf8Char symbol;
|
||||||
|
|
||||||
@@ -20,6 +20,6 @@ struct cgram_pattern {
|
|||||||
uint8_t data[8];
|
uint8_t data[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const struct cgram_pattern CGRAM_CZ[];
|
extern const struct LcdBuf_CGRAM_Symbol CGRAM_CZ[];
|
||||||
|
|
||||||
#endif //HD44780UTF_CGRAM_H
|
#endif //HD44780UTF_CGRAM_H
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
#include "utf8.h"
|
#include "utf8.h"
|
||||||
#include "cgrom.h"
|
#include "cgrom.h"
|
||||||
|
|
||||||
const struct cgrom_entry CGROM_A00[] = {
|
const struct LcdBuf_CGROM_Entry CGROM_A00[] = {
|
||||||
{.address = 32, .symbol = " "},
|
{.address = 32, .symbol = " "},
|
||||||
{.address = 33, .symbol = "!"},
|
{.address = 33, .symbol = "!"},
|
||||||
{.address = 34, .symbol = "\""},
|
{.address = 34, .symbol = "\""},
|
||||||
|
|||||||
+2
-2
@@ -9,7 +9,7 @@
|
|||||||
#include "utf8.h"
|
#include "utf8.h"
|
||||||
|
|
||||||
/** CGROM look-up table entry */
|
/** CGROM look-up table entry */
|
||||||
struct cgrom_entry {
|
struct LcdBuf_CGROM_Entry {
|
||||||
/** Address in the CGROM */
|
/** Address in the CGROM */
|
||||||
uint8_t address;
|
uint8_t address;
|
||||||
|
|
||||||
@@ -19,6 +19,6 @@ struct cgrom_entry {
|
|||||||
|
|
||||||
|
|
||||||
/** The standard japanese lookup table, terminated by an empty entry */
|
/** The standard japanese lookup table, terminated by an empty entry */
|
||||||
extern const struct cgrom_entry CGROM_A00[];
|
extern const struct LcdBuf_CGROM_Entry CGROM_A00[];
|
||||||
|
|
||||||
#endif //HD44780UTF_CGROM_H
|
#endif //HD44780UTF_CGROM_H
|
||||||
|
|||||||
+87
-52
@@ -1,14 +1,15 @@
|
|||||||
/**
|
/**
|
||||||
* TODO file description
|
* HD44780 utf8-capable display buffer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
//#include <stdio.h>
|
||||||
#include "lcdbuf.h"
|
#include "lcdbuf.h"
|
||||||
|
|
||||||
|
|
||||||
/** Initialize the struct */
|
/** Initialize the struct */
|
||||||
void LcdBuffer_Init(struct LcdBuffer *self, const struct cgrom_entry *cgrom, const struct cgram_pattern *custom_symbols)
|
void LcdBuffer_Init(struct LcdBuffer *self, const struct LcdBuf_CGROM_Entry *cgrom, const struct LcdBuf_CGRAM_Symbol *custom_symbols)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
assert(cgrom);
|
assert(cgrom);
|
||||||
@@ -25,15 +26,17 @@ void LcdBuffer_Clear(struct LcdBuffer *self)
|
|||||||
assert(self);
|
assert(self);
|
||||||
|
|
||||||
memset(self->cgram, 0, sizeof(self->cgram));
|
memset(self->cgram, 0, sizeof(self->cgram));
|
||||||
memset(self->screen, 32, sizeof(self->screen));
|
memset(self->screen, ' ', sizeof(self->screen));
|
||||||
memset(self->dirty_extents, 0, sizeof(self->dirty_extents));
|
memset(self->dirty_extents, 0, sizeof(self->dirty_extents));
|
||||||
self->full_repaint_required = false;
|
|
||||||
|
// everything must be written, who knows what was left on the display before!
|
||||||
|
self->full_repaint_required = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Write what needs to be written to the HW, clear all dirty marks */
|
/** Write what needs to be written to the HW, clear all dirty marks */
|
||||||
void LcdBuffer_Flush(struct LcdBuffer *self)
|
void LcdBuffer_Flush(struct LcdBuffer *self)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < LCDBUF_CGRAM_CAPACITY; i++) {
|
||||||
if (self->cgram[i].refcount > 0 && self->cgram[i].dirty) {
|
if (self->cgram[i].refcount > 0 && self->cgram[i].dirty) {
|
||||||
LcdBuffer_IO_WriteCGRAM(i, self->custom_symbols[self->cgram[i].symbol_index].data);
|
LcdBuffer_IO_WriteCGRAM(i, self->custom_symbols[self->cgram[i].symbol_index].data);
|
||||||
self->cgram[i].dirty = false;
|
self->cgram[i].dirty = false;
|
||||||
@@ -41,13 +44,29 @@ void LcdBuffer_Flush(struct LcdBuffer *self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (self->full_repaint_required) {
|
if (self->full_repaint_required) {
|
||||||
|
self->full_repaint_required = false;
|
||||||
|
// Check if we have anything on the display - if not, just clear screen
|
||||||
|
bool any_nonspace = false;
|
||||||
|
for (int r = 0; !any_nonspace && r < LINE_NUM; r++) {
|
||||||
|
for (int c = 0; !any_nonspace && c < LINE_LEN; c++) {
|
||||||
|
if (self->screen[r][c] != ' ') {
|
||||||
|
any_nonspace = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!any_nonspace) {
|
||||||
|
LcdBuffer_IO_Clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (int r = 0; r < LINE_NUM; r++) {
|
for (int r = 0; r < LINE_NUM; r++) {
|
||||||
LcdBuffer_IO_WriteAt(r, 0, self->screen[r], LINE_LEN);
|
LcdBuffer_IO_WriteAt(r, 0, self->screen[r], LINE_LEN);
|
||||||
}
|
}
|
||||||
memset(self->dirty_extents, 0, sizeof(self->dirty_extents));
|
memset(self->dirty_extents, 0, sizeof(self->dirty_extents));
|
||||||
} else {
|
} else {
|
||||||
for (int e = 0; e < BUFLEN_DIRTY_LIST; e++) {
|
for (int e = 0; e < LCDBUF_DIRTY_LIST_LEN; e++) {
|
||||||
struct DirtyExtent *ext = &self->dirty_extents[e];
|
struct LcdBuf_DirtyExtent *ext = &self->dirty_extents[e];
|
||||||
if (!ext->count) {
|
if (!ext->count) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -60,7 +79,7 @@ void LcdBuffer_Flush(struct LcdBuffer *self)
|
|||||||
/** Fully write everything to the display */
|
/** Fully write everything to the display */
|
||||||
void LcdBuffer_FlushAll(struct LcdBuffer *self)
|
void LcdBuffer_FlushAll(struct LcdBuffer *self)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < LCDBUF_CGRAM_CAPACITY; i++) {
|
||||||
if (self->cgram[i].refcount > 0) {
|
if (self->cgram[i].refcount > 0) {
|
||||||
LcdBuffer_IO_WriteCGRAM(i, self->custom_symbols[self->cgram[i].symbol_index].data);
|
LcdBuffer_IO_WriteCGRAM(i, self->custom_symbols[self->cgram[i].symbol_index].data);
|
||||||
}
|
}
|
||||||
@@ -75,11 +94,27 @@ void LcdBuffer_FlushAll(struct LcdBuffer *self)
|
|||||||
self->full_repaint_required = false;
|
self->full_repaint_required = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mark_dirty(struct LcdBuffer *self, uint8_t row, uint8_t col)
|
//static void show_dirty_slots(const struct LcdBuffer *self) {
|
||||||
|
// printf("\n\n");
|
||||||
|
// for (int i = 0; i < LCDBUF_DIRTY_LIST_LEN; i++) {
|
||||||
|
// if (self->dirty_extents[i].count == 0) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// printf("dirty_extent(%d): col %d, row %d, len %d\n", i, self->dirty_extents[i].row, self->dirty_extents[i].col, self->dirty_extents[i].count);
|
||||||
|
// }
|
||||||
|
// printf("\n");
|
||||||
|
//}
|
||||||
|
|
||||||
|
static void mark_dirty(struct LcdBuffer *self, lcdbuf_pos_t row, lcdbuf_pos_t col)
|
||||||
{
|
{
|
||||||
|
// partial updates are not needed if everything will be written anyway
|
||||||
|
if (self->full_repaint_required) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int first_empty_extent_slot = -1;
|
int first_empty_extent_slot = -1;
|
||||||
for (int i = 0; i < BUFLEN_DIRTY_LIST; i++) {
|
for (int i = 0; i < LCDBUF_DIRTY_LIST_LEN; i++) {
|
||||||
struct DirtyExtent *ext = &self->dirty_extents[i];
|
struct LcdBuf_DirtyExtent *ext = &self->dirty_extents[i];
|
||||||
if (ext->count == 0) {
|
if (ext->count == 0) {
|
||||||
// unused
|
// unused
|
||||||
if (first_empty_extent_slot == -1) {
|
if (first_empty_extent_slot == -1) {
|
||||||
@@ -94,60 +129,63 @@ static void mark_dirty(struct LcdBuffer *self, uint8_t row, uint8_t col)
|
|||||||
|
|
||||||
// this is a filled extent
|
// this is a filled extent
|
||||||
|
|
||||||
if (ext->col < col && ext->col + ext->count > col) {
|
if ((ext->col <= col) && (ext->col + ext->count > col)) {
|
||||||
// already in this extent
|
// already in this extent
|
||||||
|
// show_dirty_slots(self);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (col < ext->col && (ext->col - col) <= 5) {
|
if ((col < ext->col) && ((ext->col - col) <= LCDBUF_DIRTY_EXTEND)) {
|
||||||
ext->count += (ext->col - col);
|
ext->count += ext->col - col;
|
||||||
ext->col = col;
|
ext->col = col;
|
||||||
|
// show_dirty_slots(self);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (col >= ext->col + ext->count && (col - ext->col + ext->count) <= 5) {
|
if ((col >= ext->col + ext->count) && ((col - (ext->col + ext->count)) <= LCDBUF_DIRTY_EXTEND)) {
|
||||||
ext->count += (col - ext->col + ext->count);
|
ext->count += col - (ext->col + ext->count) + 1;
|
||||||
|
// show_dirty_slots(self);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (first_empty_extent_slot == -1) {
|
if (first_empty_extent_slot == -1) {
|
||||||
|
// printf("Give up on dirty extents\n");
|
||||||
self->full_repaint_required = true;
|
self->full_repaint_required = true;
|
||||||
} else {
|
} else {
|
||||||
|
// printf("New dirty extent: #%d\n", first_empty_extent_slot);
|
||||||
self->dirty_extents[first_empty_extent_slot].col = col;
|
self->dirty_extents[first_empty_extent_slot].col = col;
|
||||||
self->dirty_extents[first_empty_extent_slot].row = row;
|
self->dirty_extents[first_empty_extent_slot].row = row;
|
||||||
self->dirty_extents[first_empty_extent_slot].count = 1;
|
self->dirty_extents[first_empty_extent_slot].count = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// show_dirty_slots(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set one utf8 character at a position */
|
/** Set one utf8 character at a position */
|
||||||
void LcdBuffer_Set(struct LcdBuffer *self, uint8_t row, uint8_t col, struct Utf8Char ch)
|
void LcdBuffer_Set(struct LcdBuffer *self, lcdbuf_pos_t row, lcdbuf_pos_t col, struct Utf8Char ch)
|
||||||
{
|
{
|
||||||
|
// printf("set %d:%d\n", row, col);
|
||||||
assert(self);
|
assert(self);
|
||||||
assert(row < LINE_NUM);
|
assert(row < LINE_NUM);
|
||||||
assert(col < LINE_LEN);
|
assert(col < LINE_LEN);
|
||||||
|
|
||||||
uint8_t oldchar = self->screen[row][col];
|
const uint8_t oldchar = self->screen[row][col];
|
||||||
|
|
||||||
if (oldchar >= 8 && oldchar == ch.uint) {
|
if (oldchar >= LCDBUF_CGRAM_CAPACITY && oldchar == ch.uint) {
|
||||||
// No change
|
// No change
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast path for standard ASCII
|
// Fast path for standard ASCII - assuming this extent of the table is always the same!
|
||||||
if (ch.uint >= 32 && ch.uint < 126 && ch.uint != '\\') { // A00 has YEN in place of BACKSLASH
|
if (ch.uint >= 32 && ch.uint < 126 && ch.uint != '\\') { // A00 has YEN in place of BACKSLASH
|
||||||
// normal ASCII
|
// normal ASCII
|
||||||
if (oldchar < 8) {
|
|
||||||
// release refcount on the CGRAM cell
|
|
||||||
self->cgram[oldchar].refcount -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
self->screen[row][col] = ch.uint;
|
self->screen[row][col] = ch.uint;
|
||||||
goto done_dirty;
|
goto done_dirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find if it's in CGROM
|
// Find if it's in CGROM
|
||||||
const struct cgrom_entry *rom = self->cgrom;
|
const struct LcdBuf_CGROM_Entry *rom = self->cgrom;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (rom->symbol.uint == 0) {
|
if (rom->symbol.uint == 0) {
|
||||||
// End of the lookup table
|
// End of the lookup table
|
||||||
@@ -156,11 +194,6 @@ void LcdBuffer_Set(struct LcdBuffer *self, uint8_t row, uint8_t col, struct Utf8
|
|||||||
|
|
||||||
if (rom->symbol.uint == ch.uint) {
|
if (rom->symbol.uint == ch.uint) {
|
||||||
// found it!
|
// found it!
|
||||||
if (oldchar < 8) {
|
|
||||||
// release refcount on the CGRAM cell
|
|
||||||
self->cgram[oldchar].refcount -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
self->screen[row][col] = rom->address;
|
self->screen[row][col] = rom->address;
|
||||||
goto done_dirty;
|
goto done_dirty;
|
||||||
}
|
}
|
||||||
@@ -170,37 +203,27 @@ void LcdBuffer_Set(struct LcdBuffer *self, uint8_t row, uint8_t col, struct Utf8
|
|||||||
|
|
||||||
// Check if the same custom char is already used - if so, increment refcount and reuse it
|
// Check if the same custom char is already used - if so, increment refcount and reuse it
|
||||||
int first_empty_custom_slot = -1;
|
int first_empty_custom_slot = -1;
|
||||||
for (int i = 0; i < 8; i++) {
|
for (uint8_t slot = 0; slot < LCDBUF_CGRAM_CAPACITY; slot++) {
|
||||||
if (self->cgram[i].refcount > 0) {
|
if (self->cgram[slot].refcount > 0) {
|
||||||
if (self->cgram[i].uint == ch.uint) {
|
if (self->cgram[slot].uint == ch.uint) {
|
||||||
if (oldchar == i) {
|
if (oldchar == slot) {
|
||||||
// No change, was already the same custom
|
// No change, was already the same custom
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldchar < 8) {
|
self->cgram[slot].refcount++;
|
||||||
// release refcount on the CGRAM cell
|
self->screen[row][col] = slot;
|
||||||
self->cgram[oldchar].refcount -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
self->cgram[i].refcount += 1;
|
|
||||||
self->screen[row][col] = i;
|
|
||||||
goto done_dirty;
|
goto done_dirty;
|
||||||
}
|
}
|
||||||
} else if (first_empty_custom_slot == -1) {
|
} else if (first_empty_custom_slot == -1) {
|
||||||
first_empty_custom_slot = i;
|
first_empty_custom_slot = slot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// New custom pattern is needed
|
// New custom pattern is needed
|
||||||
|
|
||||||
if (oldchar < 8) {
|
uint16_t index = 0;
|
||||||
// release refcount on the CGRAM cell
|
const struct LcdBuf_CGRAM_Symbol *pattern = self->custom_symbols;
|
||||||
self->cgram[oldchar].refcount -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t index = 0;
|
|
||||||
const struct cgram_pattern *pattern = self->custom_symbols;
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (pattern->symbol.uint == 0) {
|
if (pattern->symbol.uint == 0) {
|
||||||
// End of the lookup table
|
// End of the lookup table
|
||||||
@@ -212,10 +235,16 @@ void LcdBuffer_Set(struct LcdBuffer *self, uint8_t row, uint8_t col, struct Utf8
|
|||||||
|
|
||||||
if (first_empty_custom_slot == -1) {
|
if (first_empty_custom_slot == -1) {
|
||||||
// Whoops, out of slots. Show a fallback glyph
|
// Whoops, out of slots. Show a fallback glyph
|
||||||
|
if (pattern->fallback != 0) {
|
||||||
if (oldchar != pattern->fallback) {
|
if (oldchar != pattern->fallback) {
|
||||||
self->screen[row][col] = pattern->fallback;
|
self->screen[row][col] = pattern->fallback;
|
||||||
goto done_dirty;
|
goto done_dirty;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// TODO kick out some other CGRAM entry that has fallback?
|
||||||
|
self->screen[row][col] = LCDBUF_SUBSTITUTION_CHAR;
|
||||||
|
goto done_dirty;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,14 +263,20 @@ void LcdBuffer_Set(struct LcdBuffer *self, uint8_t row, uint8_t col, struct Utf8
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fallback, no way to show this glyph
|
// Fallback, no way to show this glyph
|
||||||
self->screen[row][col] = '?';
|
self->screen[row][col] = LCDBUF_SUBSTITUTION_CHAR;
|
||||||
|
|
||||||
done_dirty:
|
done_dirty:
|
||||||
|
|
||||||
|
if (oldchar < LCDBUF_CGRAM_CAPACITY) {
|
||||||
|
// release refcount on the CGRAM cell
|
||||||
|
assert(self->cgram[oldchar].refcount > 0);
|
||||||
|
self->cgram[oldchar].refcount--;
|
||||||
|
}
|
||||||
mark_dirty(self, row, col);
|
mark_dirty(self, row, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Write a UTF8 string at a position */
|
/** Write a UTF8 string at a position */
|
||||||
void LcdBuffer_Write(struct LcdBuffer *self, uint8_t row, uint8_t col, char *utf_string)
|
void LcdBuffer_Write(struct LcdBuffer *self, lcdbuf_pos_t row, lcdbuf_pos_t col, char *utf_string)
|
||||||
{
|
{
|
||||||
struct Utf8Iterator iter;
|
struct Utf8Iterator iter;
|
||||||
Utf8Iterator_Init(&iter, utf_string);
|
Utf8Iterator_Init(&iter, utf_string);
|
||||||
|
|||||||
+40
-17
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* TODO file description
|
* HD44780 utf8-capable display buffer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef HD44780UTF_LCDBUF_H
|
#ifndef HD44780UTF_LCDBUF_H
|
||||||
@@ -10,28 +10,48 @@
|
|||||||
#include "cgram.h"
|
#include "cgram.h"
|
||||||
#include "cgrom.h"
|
#include "cgrom.h"
|
||||||
|
|
||||||
|
// --- settings ---
|
||||||
|
|
||||||
#define LINE_NUM 4
|
#define LINE_NUM 4
|
||||||
#define LINE_LEN 20
|
#define LINE_LEN 20
|
||||||
|
|
||||||
#define BUFLEN_DIRTY_LIST 8
|
/// number of remembered dirty regions before giving up and just writing full display
|
||||||
|
#define LCDBUF_DIRTY_LIST_LEN 8
|
||||||
|
|
||||||
|
/// if a cell is marked dirty closer than this to an existing extent,
|
||||||
|
/// the extent can grows in the direction rather than creating a new one
|
||||||
|
#define LCDBUF_DIRTY_EXTEND 5
|
||||||
|
|
||||||
|
/// Char shown if the requested symbol is missing in lookup tables
|
||||||
|
#define LCDBUF_SUBSTITUTION_CHAR 0xDB // this is the katakana box (ro ロ?) in the codepage A00
|
||||||
|
|
||||||
|
/// this must contain the full width or height
|
||||||
|
typedef uint8_t lcdbuf_pos_t;
|
||||||
|
|
||||||
|
/// this must contain the total number of cells in the display
|
||||||
|
typedef uint8_t lcdbuf_count_t;
|
||||||
_Static_assert(LINE_NUM * LINE_LEN < 256, "LINE_NUM * LINE_LEN must fit in u8");
|
_Static_assert(LINE_NUM * LINE_LEN < 256, "LINE_NUM * LINE_LEN must fit in u8");
|
||||||
|
|
||||||
|
// ----------------
|
||||||
|
|
||||||
|
/// Number of custom CGRAM slots (always 8)
|
||||||
|
#define LCDBUF_CGRAM_CAPACITY 8
|
||||||
|
|
||||||
/** Indicates a range of screen cells that were changed and must be written to HW */
|
/** Indicates a range of screen cells that were changed and must be written to HW */
|
||||||
struct DirtyExtent {
|
struct LcdBuf_DirtyExtent {
|
||||||
uint8_t row;
|
lcdbuf_pos_t row;
|
||||||
uint8_t col;
|
lcdbuf_pos_t col;
|
||||||
uint8_t count;
|
lcdbuf_count_t count;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Struct for one CGRAM slot */
|
/** Struct for one CGRAM slot */
|
||||||
struct CgramState {
|
struct LcdBuf_CgramState {
|
||||||
/** UTF8 uint shown in this slot */
|
/** UTF8 uint shown in this slot */
|
||||||
uint32_t uint;
|
uint32_t uint;
|
||||||
/** Array index in the custom symbols table, use for look-up when writing the font data to HW */
|
/** Array index in the custom symbols table, use for look-up when writing the font data to HW */
|
||||||
uint32_t symbol_index;
|
uint16_t symbol_index;
|
||||||
/** Number of occurrences of this symbol in the screen array */
|
/** Number of occurrences of this symbol in the screen array */
|
||||||
uint8_t refcount;
|
lcdbuf_count_t refcount;
|
||||||
/** This CGRAM slot needs to be written to HW */
|
/** This CGRAM slot needs to be written to HW */
|
||||||
bool dirty;
|
bool dirty;
|
||||||
};
|
};
|
||||||
@@ -40,21 +60,21 @@ struct LcdBuffer {
|
|||||||
/** The raw screen buffer. Custom symbols are 0x00-0x07 */
|
/** The raw screen buffer. Custom symbols are 0x00-0x07 */
|
||||||
uint8_t screen[LINE_NUM][LINE_LEN];
|
uint8_t screen[LINE_NUM][LINE_LEN];
|
||||||
/** CGRAM state array */
|
/** CGRAM state array */
|
||||||
struct CgramState cgram[8];
|
struct LcdBuf_CgramState cgram[LCDBUF_CGRAM_CAPACITY];
|
||||||
/** Hardware CGROM lookup table, used to map UTF8 to existing ROM symbols */
|
/** Hardware CGROM lookup table, used to map UTF8 to existing ROM symbols */
|
||||||
const struct cgrom_entry *cgrom;
|
const struct LcdBuf_CGROM_Entry *cgrom;
|
||||||
/** Defined custom display pattern of utf8 symbols */
|
/** Defined custom display pattern of utf8 symbols */
|
||||||
const struct cgram_pattern *custom_symbols;
|
const struct LcdBuf_CGRAM_Symbol *custom_symbols;
|
||||||
|
|
||||||
/** Array of dirty extents - ranges in the display that need to be flushed to HW */
|
/** Array of dirty extents - ranges in the display that need to be flushed to HW */
|
||||||
struct DirtyExtent dirty_extents[BUFLEN_DIRTY_LIST];
|
struct LcdBuf_DirtyExtent dirty_extents[LCDBUF_DIRTY_LIST_LEN];
|
||||||
/** If the dirty extents array was not sufficient to hold all changes, this flag is set,
|
/** If the dirty extents array was not sufficient to hold all changes, this flag is set,
|
||||||
* indicating the dirty_extents array should be disregarded. */
|
* indicating the dirty_extents array should be disregarded. */
|
||||||
bool full_repaint_required;
|
bool full_repaint_required;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Initialize the struct */
|
/** Initialize the struct */
|
||||||
void LcdBuffer_Init(struct LcdBuffer *self, const struct cgrom_entry *cgrom, const struct cgram_pattern *custom_symbols);
|
void LcdBuffer_Init(struct LcdBuffer *self, const struct LcdBuf_CGROM_Entry *cgrom, const struct LcdBuf_CGRAM_Symbol *custom_symbols);
|
||||||
|
|
||||||
/** Clear the screen */
|
/** Clear the screen */
|
||||||
void LcdBuffer_Clear(struct LcdBuffer *self);
|
void LcdBuffer_Clear(struct LcdBuffer *self);
|
||||||
@@ -66,15 +86,18 @@ void LcdBuffer_Flush(struct LcdBuffer *self);
|
|||||||
void LcdBuffer_FlushAll(struct LcdBuffer *self);
|
void LcdBuffer_FlushAll(struct LcdBuffer *self);
|
||||||
|
|
||||||
/** Set one utf8 character at a position */
|
/** Set one utf8 character at a position */
|
||||||
void LcdBuffer_Set(struct LcdBuffer *self, uint8_t row, uint8_t col, struct Utf8Char ch);
|
void LcdBuffer_Set(struct LcdBuffer *self, lcdbuf_pos_t row, lcdbuf_pos_t col, struct Utf8Char ch);
|
||||||
|
|
||||||
/** Write a UTF8 string at a position */
|
/** Write a UTF8 string at a position */
|
||||||
void LcdBuffer_Write(struct LcdBuffer *self, uint8_t row, uint8_t col, char *utf_string);
|
void LcdBuffer_Write(struct LcdBuffer *self, lcdbuf_pos_t row, lcdbuf_pos_t col, char *utf_string);
|
||||||
|
|
||||||
/* Callbacks - need to be implemented by the application! */
|
/* Callbacks - need to be implemented by the application! */
|
||||||
|
|
||||||
|
/** Clear the entire screen (CGRAM can be left unchanged, but they will be written anew if needed) */
|
||||||
|
void LcdBuffer_IO_Clear();
|
||||||
|
|
||||||
/** Write character data at position */
|
/** Write character data at position */
|
||||||
void LcdBuffer_IO_WriteAt(uint8_t row, uint8_t col, const uint8_t *buf, uint8_t len);
|
void LcdBuffer_IO_WriteAt(lcdbuf_pos_t row, lcdbuf_pos_t col, const uint8_t *buf, lcdbuf_count_t len);
|
||||||
|
|
||||||
/** Write CGRAM data. Data is always 8 bytes long. */
|
/** Write CGRAM data. Data is always 8 bytes long. */
|
||||||
void LcdBuffer_IO_WriteCGRAM(uint8_t position, const uint8_t* data);
|
void LcdBuffer_IO_WriteCGRAM(uint8_t position, const uint8_t* data);
|
||||||
|
|||||||
+60
-7
@@ -7,22 +7,75 @@ int main()
|
|||||||
struct LcdBuffer buf;
|
struct LcdBuffer buf;
|
||||||
LcdBuffer_Init(&buf, CGROM_A00, CGRAM_CZ);
|
LcdBuffer_Init(&buf, CGROM_A00, CGRAM_CZ);
|
||||||
|
|
||||||
LcdBuffer_Write(&buf, 0, 0, "Ahoj");
|
LcdBuffer_Write(&buf, 2, 10, "Ahoj");
|
||||||
|
LcdBuffer_Write(&buf, 2, 9, "x");
|
||||||
|
LcdBuffer_Write(&buf, 2, 6, "mm");
|
||||||
|
LcdBuffer_Write(&buf, 0, 0, "ěščžýíéů");
|
||||||
|
LcdBuffer_Write(&buf, 0, 0, "MEOWžýíéůěščřžýíéů");
|
||||||
|
|
||||||
LcdBuffer_Flush(&buf);
|
LcdBuffer_Flush(&buf);
|
||||||
|
|
||||||
|
LcdBuffer_Write(&buf, 0, 5, "ĚŠČŘŽÝ");
|
||||||
|
|
||||||
|
LcdBuffer_Flush(&buf);
|
||||||
|
|
||||||
|
LcdBuffer_Clear(&buf);
|
||||||
|
LcdBuffer_Flush(&buf);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Write character data at position */
|
/** Write character data at position */
|
||||||
void LcdBuffer_IO_WriteAt(uint8_t row, uint8_t col, const uint8_t *buf, uint8_t len)
|
void LcdBuffer_IO_Clear()
|
||||||
{
|
{
|
||||||
printf("W@%d,%d: \"%.*s\" (len %d)\n", row, col, len, buf, len);
|
printf("ClearScreen\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Write CGRAM data. Data is always 8 bytes long. */
|
/** Write character data at position */
|
||||||
void LcdBuffer_IO_WriteCGRAM(uint8_t position, const uint8_t *data)
|
void LcdBuffer_IO_WriteAt(lcdbuf_pos_t row, lcdbuf_pos_t col, const uint8_t *buf, lcdbuf_count_t len)
|
||||||
{
|
{
|
||||||
printf("G@%d: %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
printf("W@%d,%d: (len %d) \"", row, col, len); // "\n
|
||||||
position, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
|
for(int i=0; i<len; i++) {
|
||||||
|
char c = buf[i];
|
||||||
|
if (c >= 32 && c < 127) {
|
||||||
|
printf("%c", c);
|
||||||
|
} else {
|
||||||
|
printf("\\%d", c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\"\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
|
||||||
|
#define BYTE_TO_BINARY(byte) \
|
||||||
|
((byte) & 0x80 ? '#' : '.'), \
|
||||||
|
((byte) & 0x40 ? '#' : '.'), \
|
||||||
|
((byte) & 0x20 ? '#' : '.'), \
|
||||||
|
((byte) & 0x10 ? '#' : '.'), \
|
||||||
|
((byte) & 0x08 ? '#' : '.'), \
|
||||||
|
((byte) & 0x04 ? '#' : '.'), \
|
||||||
|
((byte) & 0x02 ? '#' : '.'), \
|
||||||
|
((byte) & 0x01 ? '#' : '.')
|
||||||
|
|
||||||
|
/** Write CGRAM data. Data is always 8 bytes long. */
|
||||||
|
void LcdBuffer_IO_WriteCGRAM(lcdbuf_pos_t position, const uint8_t *data)
|
||||||
|
{
|
||||||
|
printf("G@%d:\n "
|
||||||
|
BYTE_TO_BINARY_PATTERN"\n "
|
||||||
|
BYTE_TO_BINARY_PATTERN"\n "
|
||||||
|
BYTE_TO_BINARY_PATTERN"\n "
|
||||||
|
BYTE_TO_BINARY_PATTERN"\n "
|
||||||
|
BYTE_TO_BINARY_PATTERN"\n "
|
||||||
|
BYTE_TO_BINARY_PATTERN"\n "
|
||||||
|
BYTE_TO_BINARY_PATTERN"\n "
|
||||||
|
BYTE_TO_BINARY_PATTERN"\n\n",
|
||||||
|
position,
|
||||||
|
BYTE_TO_BINARY(data[0]),
|
||||||
|
BYTE_TO_BINARY(data[1]),
|
||||||
|
BYTE_TO_BINARY(data[2]),
|
||||||
|
BYTE_TO_BINARY(data[3]),
|
||||||
|
BYTE_TO_BINARY(data[4]),
|
||||||
|
BYTE_TO_BINARY(data[5]),
|
||||||
|
BYTE_TO_BINARY(data[6]),
|
||||||
|
BYTE_TO_BINARY(data[7]));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user