[2.0.x] Buffer overflow and scroll fix, UTF8 cleanup (#10844)

This commit is contained in:
Eduardo José Tagle 2018-05-26 01:32:37 -03:00 committed by Scott Lahteine
parent 235facd545
commit 6f330f397e
17 changed files with 413 additions and 671 deletions

View file

@ -162,22 +162,15 @@ void spiBegin (void) {
// away. When clock is not known, use a loop instead, which generates // away. When clock is not known, use a loop instead, which generates
// shorter code. // shorter code.
if (__builtin_constant_p(spiClock)) { if (__builtin_constant_p(spiClock)) {
if (spiClock >= F_CPU / 2) { if (spiClock >= F_CPU / 2) clockDiv = 0;
clockDiv = 0; else if (spiClock >= F_CPU / 4) clockDiv = 1;
} else if (spiClock >= F_CPU / 4) { else if (spiClock >= F_CPU / 8) clockDiv = 2;
clockDiv = 1; else if (spiClock >= F_CPU / 16) clockDiv = 3;
} else if (spiClock >= F_CPU / 8) { else if (spiClock >= F_CPU / 32) clockDiv = 4;
clockDiv = 2; else if (spiClock >= F_CPU / 64) clockDiv = 5;
} else if (spiClock >= F_CPU / 16) { else clockDiv = 6;
clockDiv = 3;
} else if (spiClock >= F_CPU / 32) {
clockDiv = 4;
} else if (spiClock >= F_CPU / 64) {
clockDiv = 5;
} else {
clockDiv = 6;
} }
} else { else {
uint32_t clockSetting = F_CPU / 2; uint32_t clockSetting = F_CPU / 2;
clockDiv = 0; clockDiv = 0;
while (clockDiv < 6 && spiClock < clockSetting) { while (clockDiv < 6 && spiClock < clockSetting) {
@ -187,8 +180,7 @@ void spiBegin (void) {
} }
// Compensate for the duplicate fosc/64 // Compensate for the duplicate fosc/64
if (clockDiv == 6) if (clockDiv == 6) clockDiv = 7;
clockDiv = 7;
// Invert the SPI2X bit // Invert the SPI2X bit
clockDiv ^= 0x1; clockDiv ^= 0x1;

View file

@ -56,7 +56,6 @@ extern uint8_t ubl_cnt;
/////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////
#if ENABLED(ULTRA_LCD) #if ENABLED(ULTRA_LCD)
extern char lcd_status_message[];
void lcd_quick_feedback(const bool clear_buttons); void lcd_quick_feedback(const bool clear_buttons);
#endif #endif

View file

@ -135,10 +135,6 @@
// External references // External references
#if ENABLED(ULTRA_LCD)
extern char lcd_status_message[];
#endif
// Private functions // Private functions
static uint16_t circle_flags[16], horizontal_mesh_line_flags[16], vertical_mesh_line_flags[16]; static uint16_t circle_flags[16], horizontal_mesh_line_flags[16], vertical_mesh_line_flags[16];
@ -508,8 +504,6 @@ inline bool prime_nozzle() {
wait_for_release(); wait_for_release();
strcpy_P(lcd_status_message, PSTR("Done Priming")); // Hack to get the message up. May be obsolete.
lcd_setstatusPGM(PSTR("Done Priming"), 99); lcd_setstatusPGM(PSTR("Done Priming"), 99);
lcd_quick_feedback(true); lcd_quick_feedback(true);
lcd_external_control = false; lcd_external_control = false;

View file

@ -519,15 +519,12 @@ void GcodeSuite::G33() {
} }
// Report settings // Report settings
const char* checkingac = PSTR("Checking... AC");
const char *checkingac = PSTR("Checking... AC");
serialprintPGM(checkingac); serialprintPGM(checkingac);
if (verbose_level == 0) SERIAL_PROTOCOLPGM(" (DRY-RUN)"); if (verbose_level == 0) SERIAL_PROTOCOLPGM(" (DRY-RUN)");
if (set_up) SERIAL_PROTOCOLPGM(" (SET-UP)"); if (set_up) SERIAL_PROTOCOLPGM(" (SET-UP)");
SERIAL_EOL(); SERIAL_EOL();
char mess[11]; lcd_setstatusPGM(checkingac);
strcpy_P(mess, checkingac);
lcd_setstatus(mess);
print_calibration_settings(_endstop_results, _angle_results); print_calibration_settings(_endstop_results, _angle_results);

View file

@ -33,7 +33,7 @@ FORCE_INLINE void _draw_centered_temp(const int16_t temp, const uint8_t x, const
const char * const str = itostr3(temp); const char * const str = itostr3(temp);
lcd_moveto(x - (str[0] != ' ' ? 0 : str[1] != ' ' ? 1 : 2) * DOG_CHAR_WIDTH / 2, y); lcd_moveto(x - (str[0] != ' ' ? 0 : str[1] != ' ' ? 1 : 2) * DOG_CHAR_WIDTH / 2, y);
lcd_put_u8str(str); lcd_put_u8str(str);
lcd_put_u8str_rom(PSTR(LCD_STR_DEGREE " ")); lcd_put_u8str_P(PSTR(LCD_STR_DEGREE " "));
} }
#ifndef HEAT_INDICATOR_X #ifndef HEAT_INDICATOR_X
@ -113,7 +113,7 @@ FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const
else { else {
#if DISABLED(HOME_AFTER_DEACTIVATE) && DISABLED(DISABLE_REDUCED_ACCURACY_WARNING) #if DISABLED(HOME_AFTER_DEACTIVATE) && DISABLED(DISABLE_REDUCED_ACCURACY_WARNING)
if (!axis_known_position[axis]) if (!axis_known_position[axis])
lcd_put_u8str_rom(axis == Z_AXIS ? PSTR(" ") : PSTR(" ")); lcd_put_u8str_P(axis == Z_AXIS ? PSTR(" ") : PSTR(" "));
else else
#endif #endif
lcd_put_u8str(value); lcd_put_u8str(value);
@ -124,36 +124,77 @@ FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const
inline void lcd_implementation_status_message(const bool blink) { inline void lcd_implementation_status_message(const bool blink) {
#if ENABLED(STATUS_MESSAGE_SCROLLING) #if ENABLED(STATUS_MESSAGE_SCROLLING)
static bool last_blink = false; static bool last_blink = false;
const uint8_t slen = utf8_strlen(lcd_status_message);
const char *stat = lcd_status_message + status_scroll_pos; // Get the UTF8 character count of the string
if (slen <= LCD_WIDTH) uint8_t slen = utf8_strlen(lcd_status_message);
lcd_put_u8str(stat); // The string isn't scrolling
else { // If the string fits into the LCD, just print it and do not scroll it
if (status_scroll_pos <= slen - LCD_WIDTH) if (slen <= LCD_WIDTH) {
lcd_put_u8str(stat); // The string fills the screen
else { // The string isn't scrolling and may not fill the screen
uint8_t chars = LCD_WIDTH; lcd_put_u8str(lcd_status_message);
if (status_scroll_pos < slen) { // First string still visible
lcd_put_u8str(stat); // The string leaves space // Fill the rest with spaces
chars -= slen - status_scroll_pos; // Amount of space left while (slen < LCD_WIDTH) {
lcd_put_wchar(' ');
++slen;
} }
}
else {
// String is larger than the available space in screen.
// Get a pointer to the next valid UTF8 character
const char *stat = lcd_status_message + status_scroll_offset;
// Get the string remaining length
const uint8_t rlen = utf8_strlen(stat);
// If we have enough characters to display
if (rlen >= LCD_WIDTH) {
// The remaining string fills the screen - Print it
lcd_put_u8str_max(stat, LCD_PIXEL_WIDTH);
}
else {
// The remaining string does not completely fill the screen
lcd_put_u8str_max(stat, LCD_PIXEL_WIDTH); // The string leaves space
uint8_t chars = LCD_WIDTH - rlen; // Amount of space left in characters
lcd_put_wchar('.'); // Always at 1+ spaces left, draw a dot lcd_put_wchar('.'); // Always at 1+ spaces left, draw a dot
if (--chars) { // Draw a second dot if there's space
lcd_put_wchar('.');
if (--chars) { if (--chars) {
if (status_scroll_pos < slen + 1) // Draw a second dot if there's space // Print a second copy of the message
--chars, lcd_put_wchar('.'); lcd_put_u8str_max(lcd_status_message, LCD_PIXEL_WIDTH - ((rlen+2) * DOG_CHAR_WIDTH));
if (chars) lcd_put_u8str_max(lcd_status_message, chars); // Print a second copy of the message }
} }
} }
if (last_blink != blink) { if (last_blink != blink) {
last_blink = blink; last_blink = blink;
// Skip any non-printing bytes
if (status_scroll_pos < slen) while (!PRINTABLE(lcd_status_message[status_scroll_pos])) status_scroll_pos++; // Adjust by complete UTF8 characters
if (++status_scroll_pos >= slen + 2) status_scroll_pos = 0; if (status_scroll_offset < slen) {
status_scroll_offset++;
while (!START_OF_UTF8_CHAR(lcd_status_message[status_scroll_offset]))
status_scroll_offset++;
}
else
status_scroll_offset = 0;
} }
} }
#else #else
UNUSED(blink); UNUSED(blink);
lcd_put_u8str(lcd_status_message);
// Get the UTF8 character count of the string
uint8_t slen = utf8_strlen(lcd_status_message);
// Just print the string to the LCD
lcd_put_u8str_max(lcd_status_message, LCD_PIXEL_WIDTH);
// Fill the rest with spaces if there are missing spaces
while (slen < LCD_WIDTH) {
lcd_put_wchar(' ');
++slen;
}
#endif #endif
} }
@ -417,7 +458,7 @@ static void lcd_implementation_status_screen() {
lcd_put_wchar('%'); lcd_put_wchar('%');
lcd_setFont(FONT_MENU); lcd_setFont(FONT_MENU);
lcd_moveto(47, 50); lcd_moveto(47, 50);
lcd_put_wchar(LCD_STR_FILAM_DIA[0]); // lcd_put_u8str_rom(PSTR(LCD_STR_FILAM_DIA)); lcd_put_wchar(LCD_STR_FILAM_DIA[0]); // lcd_put_u8str_P(PSTR(LCD_STR_FILAM_DIA));
lcd_moveto(93, 50); lcd_moveto(93, 50);
lcd_put_wchar(LCD_STR_FILAM_MUL[0]); lcd_put_wchar(LCD_STR_FILAM_MUL[0]);
#endif #endif
@ -437,10 +478,10 @@ static void lcd_implementation_status_screen() {
lcd_implementation_status_message(blink); lcd_implementation_status_message(blink);
} }
else { else {
lcd_put_u8str_rom(PSTR(LCD_STR_FILAM_DIA)); lcd_put_u8str_P(PSTR(LCD_STR_FILAM_DIA));
lcd_put_wchar(':'); lcd_put_wchar(':');
lcd_put_u8str(wstring); lcd_put_u8str(wstring);
lcd_put_u8str_rom(PSTR(" " LCD_STR_FILAM_MUL)); lcd_put_u8str_P(PSTR(" " LCD_STR_FILAM_MUL));
lcd_put_wchar(':'); lcd_put_wchar(':');
lcd_put_u8str(mstring); lcd_put_u8str(mstring);
lcd_put_wchar('%'); lcd_put_wchar('%');

View file

@ -615,36 +615,71 @@ void ST7920_Lite_Status_Screen::draw_feedrate_percentage(const uint8_t percentag
void ST7920_Lite_Status_Screen::draw_status_message(const char *str) { void ST7920_Lite_Status_Screen::draw_status_message(const char *str) {
set_ddram_address(DDRAM_LINE_4); set_ddram_address(DDRAM_LINE_4);
begin_data(); begin_data();
#if ENABLED(STATUS_MESSAGE_SCROLLING)
const uint8_t lcd_len = 16; const uint8_t lcd_len = 16;
const uint8_t padding = 2; #if ENABLED(STATUS_MESSAGE_SCROLLING)
uint8_t str_len = strlen(str);
// Trim whitespace at the end of the str, as for some reason uint8_t slen = utf8_strlen(str);
// messages like "Card Inserted" are padded with many spaces
while (str_len && str[str_len - 1] == ' ') str_len--;
if (str_len <= lcd_len) { // If the string fits into the LCD, just print it and do not scroll it
// It all fits on the LCD without scrolling if (slen <= lcd_len) {
// The string isn't scrolling and may not fill the screen
write_str(str); write_str(str);
// Fill the rest with spaces
while (slen < lcd_len) {
write_byte(' ');
++slen;
}
} }
else { else {
// Print the message repeatedly until covering the LCD // String is larger than the available space in screen.
uint8_t c = status_scroll_pos;
for (uint8_t n = 0; n < lcd_len; n++) { // Get a pointer to the next valid UTF8 character
write_byte(c < str_len ? str[c] : ' '); const char *stat = str + status_scroll_offset;
c++;
c %= str_len + padding; // Wrap around // Get the string remaining length
const uint8_t rlen = utf8_strlen(stat);
// If we have enough characters to display
if (rlen >= lcd_len) {
// The remaining string fills the screen - Print it
write_str(stat, lcd_len);
}
else {
// The remaining string does not completely fill the screen
write_str(stat); // The string leaves space
uint8_t chars = lcd_len - rlen; // Amount of space left in characters
write_byte('.'); // Always at 1+ spaces left, draw a dot
if (--chars) { // Draw a second dot if there's space
write_byte('.');
if (--chars)
write_str(str, chars); // Print a second copy of the message
}
} }
// Scroll the message // Adjust by complete UTF8 characters
if (status_scroll_pos == str_len + padding) if (status_scroll_offset < slen) {
status_scroll_pos = 0; status_scroll_offset++;
while (!START_OF_UTF8_CHAR(str[status_scroll_offset]))
status_scroll_offset++;
}
else else
status_scroll_pos++; status_scroll_offset = 0;
} }
#else #else
write_str(str, 16); // Get the UTF8 character count of the string
uint8_t slen = utf8_strlen(str);
// Just print the string to the LCD
write_str(str, lcd_len);
// Fill the rest with spaces if there are missing spaces
while (slen < lcd_len) {
write_byte(' ');
++slen;
}
#endif #endif
} }
@ -792,7 +827,7 @@ void ST7920_Lite_Status_Screen::update_status_or_position(bool forceUpdate) {
*/ */
if (forceUpdate || status_changed()) { if (forceUpdate || status_changed()) {
#if ENABLED(STATUS_MESSAGE_SCROLLING) #if ENABLED(STATUS_MESSAGE_SCROLLING)
status_scroll_pos = 0; status_scroll_offset = 0;
#endif #endif
#if STATUS_EXPIRE_SECONDS #if STATUS_EXPIRE_SECONDS
countdown = lcd_status_message[0] ? STATUS_EXPIRE_SECONDS : 0; countdown = lcd_status_message[0] ? STATUS_EXPIRE_SECONDS : 0;

View file

@ -16,56 +16,14 @@
#include "fontutils.h" #include "fontutils.h"
uint8_t read_byte_ram(uint8_t * str) { return *str; } uint8_t read_byte_ram(uint8_t * str) {
uint8_t read_byte_rom(uint8_t * str) { return pgm_read_byte(str); } return *str;
}
#if DEBUG uint8_t read_byte_rom(uint8_t * str) {
#ifdef ARDUINO return pgm_read_byte(str);
#include <Arduino.h> }
#include <stdarg.h>
void serial_printf_P(const char *format, ...) {
static char buff[128];
va_list args;
va_start(args,format);
vsnprintf_P(buff,sizeof(buff),format,args);
va_end(args);
buff[sizeof(buff)/sizeof(buff[0])-1]='\0';
//Serial.print(buff);
SERIAL_ECHO(buff); SERIAL_EOL;
}
#endif
#endif
#ifdef __WIN32__ // or whatever
#define PRIiSZ "ld"
#define PRIuSZ "Iu"
#else
#define PRIiSZ "zd"
#define PRIuSZ "zu"
#endif
#define PRIiOFF "lld"
#define PRIuOFF "llu"
#define DBGMSG(a,b, ...) TRACE( #__VA_ARGS__ )
//typedef int (* pf_bsearch_cb_comp_t)(void *userdata, size_t idx, void * data_pin); /*"data_list[idx] - *data_pin"*/
/**
* @brief
*
* @param userdata :
* @param num_data :
* @param cb_comp :
* @param data_pinpoint :
* @param ret_idx : ;
*
* @return 0<0
*
* , psl->marr
*/
/** /**
* @brief Using binary search to find the position by data_pin * @brief Using binary search to find the position by data_pin
* *
@ -82,21 +40,11 @@ uint8_t read_byte_rom(uint8_t * str) { return pgm_read_byte(str); }
int pf_bsearch_r(void *userdata, size_t num_data, pf_bsearch_cb_comp_t cb_comp, void *data_pinpoint, size_t *ret_idx) { int pf_bsearch_r(void *userdata, size_t num_data, pf_bsearch_cb_comp_t cb_comp, void *data_pinpoint, size_t *ret_idx) {
int retcomp; int retcomp;
FU_ASSERT(NULL != ret_idx);
/* 查找合适的位置 */
if (num_data < 1) { if (num_data < 1) {
*ret_idx = 0; *ret_idx = 0;
DBGMSG (PFDBG_CATLOG_PF, PFDBG_LEVEL_ERROR, "num_data(%" PRIuSZ ") < 1", num_data);
return -1; return -1;
} }
/* 折半查找 */
/* 为了不出现负数,以免缩小索引的所表示的数据范围
* (使)
* ileft iright使用从1开始的下标
* 1C语言中的0, 21
* 使 0
*/
size_t i = 0, ileft = 1, iright = num_data; size_t i = 0, ileft = 1, iright = num_data;
bool flg_found = false; bool flg_found = false;
for (; ileft <= iright;) { for (; ileft <= iright;) {
@ -122,28 +70,15 @@ int pf_bsearch_r(void *userdata, size_t num_data, pf_bsearch_cb_comp_t cb_comp,
*ret_idx = i; *ret_idx = i;
else if (ileft >= i + 2) else if (ileft >= i + 2)
*ret_idx = i + 1; *ret_idx = i + 1;
//DBGMSG (PFDBG_CATLOG_PF, PFDBG_LEVEL_DEBUG, "not found! num_data=%" PRIuSZ "; ileft=%" PRIuSZ ", iright=%" PRIuSZ ", i=%" PRIuSZ "", num_data, ileft, iright, i);
return -1; return -1;
} }
/** /* This function gets the character at the pstart position, interpreting UTF8 multybyte sequences
* @brief UTF-8 Unicode (wchar_t) and returns the pointer to the next character */
*
* @param pstart : UTF-8
* @param cb_read_byte : 8MCU ROM
* @param pval : Unicode
*
* @return UTF-8
*
* UTF-8 Unicode (wchar_t)
*/
uint8_t* get_utf8_value_cb(uint8_t *pstart, read_byte_cb_t cb_read_byte, wchar_t *pval) { uint8_t* get_utf8_value_cb(uint8_t *pstart, read_byte_cb_t cb_read_byte, wchar_t *pval) {
uint32_t val = 0; uint32_t val = 0;
uint8_t *p = pstart; uint8_t *p = pstart;
FU_ASSERT(NULL != pstart);
FU_ASSERT(NULL != cb_read_byte);
uint8_t valcur = cb_read_byte(p); uint8_t valcur = cb_read_byte(p);
if (0 == (0x80 & valcur)) { if (0 == (0x80 & valcur)) {
val = valcur; val = valcur;
@ -215,113 +150,34 @@ uint8_t* get_utf8_value_cb(uint8_t *pstart, read_byte_cb_t cb_read_byte, wchar_t
val |= (valcur & 0x3F); val |= (valcur & 0x3F);
p++; p++;
} }
else if (0x80 == (0xC0 & valcur)) { else if (0x80 == (0xC0 & valcur))
/* error? */
TRACE("ERR 1");
for (; 0x80 == (0xC0 & valcur); ) { p++; valcur = cb_read_byte(p); } for (; 0x80 == (0xC0 & valcur); ) { p++; valcur = cb_read_byte(p); }
} else
else {
/* error */
TRACE("ERR 2");
for (; ((0xFE & valcur) > 0xFC); ) { p++; valcur = cb_read_byte(p); } for (; ((0xFE & valcur) > 0xFC); ) { p++; valcur = cb_read_byte(p); }
}
/*
if (val == 0) {
p = NULL;
*/
/*
}
else if (pstart + maxlen < p) {
p = pstart;
if (pval) *pval = 0;
}
*/
if (pval) *pval = val; if (pval) *pval = val;
return p; return p;
} }
// uint8_t * get_utf8_value_cb (uint8_t *pstart, read_byte_cb_t cb_read_byte, wchar_t *pval); static inline uint8_t utf8_strlen_cb(const char *pstart, read_byte_cb_t cb_read_byte) {
int utf8_strlen_cb(const char *pstart, read_byte_cb_t cb_read_byte) {
wchar_t ch;
uint8_t *pnext;
int cnt = 0;
for (pnext = (uint8_t *)pstart; ; ) { uint8_t cnt = 0;
uint8_t *pnext = (uint8_t *)pstart;
for (;;) {
wchar_t ch;
pnext = get_utf8_value_cb(pnext, cb_read_byte, &ch); pnext = get_utf8_value_cb(pnext, cb_read_byte, &ch);
if (pnext == NULL || ch == 0) break; if (!ch) break;
cnt++; cnt++;
TRACE("cnt=%d, ch=0x%X", cnt, (int)ch);
} }
return cnt; return cnt;
} }
int uint8_t utf8_strlen(const char *pstart) {
my_strlen_P(const char *pstart) return utf8_strlen_cb(pstart, read_byte_ram);
{
const char *p;
FU_ASSERT(NULL != pstart);
p = pstart;
while (p && pgm_read_byte(p) != '\0') p ++;
return (p - pstart);
} }
uint8_t utf8_strlen(const char *pstart) { return utf8_strlen_cb(pstart, read_byte_ram); } uint8_t utf8_strlen_P(const char *pstart) {
uint8_t utf8_strlen_P(const char *pstart) { return utf8_strlen_cb(pstart, read_byte_rom); } return utf8_strlen_cb(pstart, read_byte_rom);
char* utf8_strncpy_cb( char * destination, const char *source, size_t num, int len_src, read_byte_cb_t cb_read_byte) {
uint8_t *p = (uint8_t *)source;
uint8_t *d = (uint8_t *)destination;
FU_ASSERT(NULL != destination);
FU_ASSERT(NULL != source);
FU_ASSERT(NULL != cb_read_byte);
uint8_t *pend = p + len_src;
while (p < pend) {
uint8_t valcur = cb_read_byte(p);
size_t len = 0;
if (0 == (0x80 & valcur))
len = 1;
else if (0xC0 == (0xE0 & valcur))
len = 2;
else if (0xE0 == (0xF0 & valcur))
len = 3;
else if (0xF0 == (0xF8 & valcur))
len = 4;
else if (0xF8 == (0xFC & valcur))
len = 5;
else if (0xFC == (0xFE & valcur))
len = 6;
else if (0x80 == (0xC0 & valcur)) {
/* error? */
for (; 0x80 == (0xC0 & valcur) && (p < pend); ) { p++; valcur = cb_read_byte(p); }
}
else {
/* error */
for (; ((0xFE & valcur) > 0xFC) && (p < pend); ) { p++; valcur = cb_read_byte(p); }
}
if (len < num) {
for (size_t i = 0; i < len; i++) {
valcur = cb_read_byte(p);
*d = valcur;
d++;
p++;
}
}
else
break;
}
*d = 0;
return destination;
} }
char* utf8_strncpy(char * destination, const char * source, size_t num) {
return utf8_strncpy_cb(destination, source, num, strlen(source), read_byte_ram);
}
char* utf8_strncpy_P(char * destination, const char * source, size_t num) {
return utf8_strncpy_cb(destination, source, num, my_strlen_P(source), read_byte_rom);
}

View file

@ -9,151 +9,40 @@
#ifndef _FONT_UTILS_H #ifndef _FONT_UTILS_H
#define _FONT_UTILS_H #define _FONT_UTILS_H
#define DEBUG 0 #include <Arduino.h>
#include "../core/macros.h"
#ifdef ARDUINO
#include <Arduino.h>
#else // ARDUINO
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#endif // ARDUINO
#ifndef pgm_read_word_near // __AVR__
#include <stdint.h>
#include <string.h>
#include <assert.h>
//#define pgm_read_word_near(a) *((uint16_t *)(a))
#define pgm_read_word_near(a) (*(a))
#define pgm_read_byte_near(a) *((uint8_t *)(a))
#define pgm_read_byte pgm_read_byte_near
#elif defined(__AVR__)
#include <avr/pgmspace.h>
#endif
#ifndef PROGMEM
#define PROGMEM
#define strlen_P strlen
#define memcpy_P memcpy
#define vsnprintf_P vsnprintf
#endif // PROGMEM
#ifdef __cplusplus
extern "C" {
#endif
// read a byte from ROM or RAM
typedef uint8_t (* read_byte_cb_t)(uint8_t * str);
//inline uint8_t read_byte_ram(uint8_t * str) { return *str; }
//inline uint8_t read_byte_rom(uint8_t * str) { return pgm_read_byte(str); }
uint8_t read_byte_ram(uint8_t * str);
uint8_t read_byte_rom(uint8_t * str);
#ifdef __cplusplus
}
#endif
#include <stddef.h> // wchar_t #include <stddef.h> // wchar_t
#include <stdint.h> // uint32_t #include <stdint.h> // uint32_t
#ifdef ARDUINO // read a byte from ROM or RAM
typedef uint8_t (*read_byte_cb_t)(uint8_t * str);
// there's overflow of the wchar_t due to the 2-byte size in Arduino uint8_t read_byte_ram(uint8_t * str);
// sizeof(wchar_t)=2; sizeof(size_t)=2; sizeof(uint32_t)=4; uint8_t read_byte_rom(uint8_t * str);
// sizeof(int)=2; sizeof(long)=4; sizeof(unsigned)=2;
//#undef wchar_t
#define wchar_t uint32_t
//typedef uint32_t wchar_t;
#else // there's overflow of the wchar_t due to the 2-byte size in Arduino
// sizeof(wchar_t)=2; sizeof(size_t)=2; sizeof(uint32_t)=4;
#include <sys/types.h> // ssize_t // sizeof(int)=2; sizeof(long)=4; sizeof(unsigned)=2;
#include <assert.h> //#undef wchar_t
// x86_64 #define wchar_t uint32_t
// sizeof(wchar_t)=4; sizeof(size_t)=8; sizeof(uint32_t)=4; //typedef uint32_t wchar_t;
// sizeof(int)=4; sizeof(long)=8; sizeof(unsigned)=4;
//#define wchar_t uint32_t
#define wchar_t size_t
#ifndef PRIu32
#define PRIu32 "lu"
#endif
#ifndef PRIX32
#define PRIX32 "lX"
#endif
#endif
#define UNUSED_VARIABLE(a) ((void)(a))
#ifndef MIN
#define MIN(a,b) (((a)>(b))?(b):(a))
#endif
#ifndef NUM_ARRAY #ifndef NUM_ARRAY
#define NUM_ARRAY(a) (sizeof(a)/sizeof((a)[0])) #define NUM_ARRAY(a) (sizeof(a)/sizeof((a)[0]))
#endif // NUM_ARRAY #endif // NUM_ARRAY
typedef uint16_t pixel_len_t;
#ifdef __cplusplus
extern "C" {
#endif
//#define pixel_len_t u8g_uint_t
#define pixel_len_t uint16_t
//#define pixel_len_t uint8_t
//typedef uint16_t pixel_len_t;
#define PIXEL_LEN_NOLIMIT ((pixel_len_t)(-1)) #define PIXEL_LEN_NOLIMIT ((pixel_len_t)(-1))
/* Perform binary search */
typedef int (* pf_bsearch_cb_comp_t)(void *userdata, size_t idx, void * data_pin); /*"data_list[idx] - *data_pin"*/ typedef int (* pf_bsearch_cb_comp_t)(void *userdata, size_t idx, void * data_pin); /*"data_list[idx] - *data_pin"*/
int pf_bsearch_r(void *userdata, size_t num_data, pf_bsearch_cb_comp_t cb_comp, void *data_pinpoint, size_t *ret_idx); int pf_bsearch_r(void *userdata, size_t num_data, pf_bsearch_cb_comp_t cb_comp, void *data_pinpoint, size_t *ret_idx);
//wchar_t get_val_utf82uni(uint8_t *pstart); /* Get the character, decoding multibyte UTF8 characters and returning a pointer to the start of the next UTF8 character */
//uint8_t * get_utf8_value(uint8_t *pstart, wchar_t *pval); uint8_t* get_utf8_value_cb(uint8_t *pstart, read_byte_cb_t cb_read_byte, wchar_t *pval);
uint8_t * get_utf8_value_cb(uint8_t *pstart, read_byte_cb_t cb_read_byte, wchar_t *pval);
/* Returns lenght of string in CHARACTERS, NOT BYTES */
uint8_t utf8_strlen(const char *pstart); uint8_t utf8_strlen(const char *pstart);
uint8_t utf8_strlen_P(const char *pstart); uint8_t utf8_strlen_P(const char *pstart);
char * utf8_strncpy(char * destination, const char * source, size_t num);
char * utf8_strncpy_P(char * destination, const char * source, size_t num);
int my_strlen_P(const char *pstart);
#if 0 // DEBUG
#if 0 //defined(ARDUINO)
#if defined(__AVR__)
#define TRACE(fmt, ...) {static const PROGMEM char CONSTSTR[] = "%d %d " fmt " {ln:%d;}\n"; serial_printf_P(CONSTSTR, millis(), ##__VA_ARGS__, __LINE__); }
#else
#define TRACE(fmt, ...) {static const PROGMEM char CONSTSTR[] = "%d " fmt " {ln:%d, fn:" __FILE__ "}\n"; serial_printf_P(CONSTSTR, millis(), ##__VA_ARGS__, __LINE__); }
#endif
#define FU_ASSERT(a) if (!(a)) {TRACE("Assert: " # a ); }
#ifdef __cplusplus
extern "C" {
#endif
void serial_printf_P(const char *format, ...);
#ifdef __cplusplus
}
#endif
#else // ARDUINO
#include <stdio.h>
#define FU_ASSERT(a) if (!(a)) {printf("Assert: " # a); exit(1);}
#define TRACE(fmt, ...) fprintf(stdout, "[%s()] " fmt " {ln:%d, fn:" __FILE__ "}\n", __func__, ##__VA_ARGS__, __LINE__)
//#else
//#define FU_ASSERT(a)
//#define TRACE(...)
#endif // ARDUINO
#else // DEBUG
#define TRACE(fmt, ...)
#define FU_ASSERT(a)
#endif // DEBUG
#ifdef __cplusplus
}
#endif
#endif // _FONT_UTILS_H #endif // _FONT_UTILS_H

View file

@ -17,11 +17,7 @@
#include "u8g_fontutf8.h" #include "u8g_fontutf8.h"
#endif #endif
#define PRINTABLE(C) (((C) & 0xC0u) != 0x80u) #define START_OF_UTF8_CHAR(C) (((C) & 0xC0u) != 0x80u)
#ifdef __cplusplus
extern "C" {
#endif
int lcd_glyph_height(void); int lcd_glyph_height(void);
@ -49,15 +45,11 @@ int lcd_put_u8str_max(const char * utf8_str, pixel_len_t max_length);
* *
* Draw a ROM UTF-8 string * Draw a ROM UTF-8 string
*/ */
int lcd_put_u8str_max_rom(const char * utf8_str_P, pixel_len_t max_length); int lcd_put_u8str_max_P(const char * utf8_str_P, pixel_len_t max_length);
void lcd_moveto(int col, int row); void lcd_moveto(int col, int row);
#ifdef __cplusplus inline int lcd_put_u8str_P(const char *str) { return lcd_put_u8str_max_P(str, PIXEL_LEN_NOLIMIT); }
}
#endif
#define lcd_put_u8str_rom(str) lcd_put_u8str_max_rom(str, PIXEL_LEN_NOLIMIT)
inline int lcd_put_u8str(const char* str) { return lcd_put_u8str_max(str, PIXEL_LEN_NOLIMIT); } inline int lcd_put_u8str(const char* str) { return lcd_put_u8str_max(str, PIXEL_LEN_NOLIMIT); }

View file

@ -24,20 +24,13 @@
#include "fontutils.h" #include "fontutils.h"
#include "lcdprint.h" #include "lcdprint.h"
#if defined(ARDUINO) #include "ultralcd_common_HD44780.h"
#include "ultralcd_common_HD44780.h" #ifndef LCD_CLASS
#ifndef LCD_CLASS
#include <LiquidCrystal.h> #include <LiquidCrystal.h>
#define LCD_CLASS LiquidCrystal #define LCD_CLASS LiquidCrystal
#endif
extern LCD_CLASS lcd;
LCD_CLASS *plcd = &lcd;
#define _lcd_write(a) plcd->write(a)
#define _lcd_setcursor(col, row) plcd->setCursor((col), (row));
#else
#define _lcd_write(a) TRACE("Write LCD: %c (%d)", (a), (int)(a));
#define _lcd_setcursor(col, row) TRACE("Set cursor LCD: (%d,%d)", (col), (row));
#endif #endif
extern LCD_CLASS lcd;
LCD_CLASS *plcd = &lcd;
int lcd_glyph_height(void) { return 1; } int lcd_glyph_height(void) { return 1; }
@ -878,25 +871,10 @@ static const hd44780_charmap_t g_hd44780_charmap_common[] PROGMEM = {
/* return v1 - v2 */ /* return v1 - v2 */
static int hd44780_charmap_compare(hd44780_charmap_t * v1, hd44780_charmap_t * v2) { static int hd44780_charmap_compare(hd44780_charmap_t * v1, hd44780_charmap_t * v2) {
FU_ASSERT(NULL != v1); if (v1->uchar < v2->uchar)
FU_ASSERT(NULL != v2);
TRACE("compare char1 %" PRIu32 "(0x%" PRIX32 ")", v1->uchar, v1->uchar);
TRACE("compare char2 %" PRIu32 "(0x%" PRIX32 ")", v2->uchar, v2->uchar);
if (v1->uchar < v2->uchar) {
TRACE("compare return -1");
return -1; return -1;
} else if (v1->uchar > v2->uchar) { else if (v1->uchar > v2->uchar)
TRACE("compare return 1");
return 1; return 1;
}
#if 0
if (v1->idx < v2->idx) {
return -1;
} else if (v1->idx > v2->idx) {
return 1;
}
#endif
TRACE("compare return 0");
return 0; return 0;
} }
@ -909,9 +887,7 @@ static int pf_bsearch_cb_comp_hd4map_pgm(void *userdata, size_t idx, void * data
#if DEBUG #if DEBUG
int int test_hd44780_charmap(hd44780_charmap_t *data, size_t size, char *name, char flg_show_contents) {
test_hd44780_charmap(hd44780_charmap_t *data, size_t size, char *name, char flg_show_contents)
{
int ret; int ret;
size_t idx = 0; size_t idx = 0;
hd44780_charmap_t preval = {0, 0, 0}; hd44780_charmap_t preval = {0, 0, 0};
@ -963,9 +939,7 @@ test_hd44780_charmap(hd44780_charmap_t *data, size_t size, char *name, char flg_
return 0; return 0;
} }
int int test_hd44780_charmap_all(void) {
test_hd44780_charmap_all(void)
{
int flg_error = 0; int flg_error = 0;
if (test_hd44780_charmap(g_hd44780_charmap_device, NUM_ARRAY(g_hd44780_charmap_device), "g_hd44780_charmap_device", 0) < 0) { if (test_hd44780_charmap(g_hd44780_charmap_device, NUM_ARRAY(g_hd44780_charmap_device), "g_hd44780_charmap_device", 0) < 0) {
flg_error = 1; flg_error = 1;
@ -986,18 +960,17 @@ test_hd44780_charmap_all(void)
#endif // DEBUG #endif // DEBUG
void lcd_moveto(int col, int row) { void lcd_moveto(int col, int row) {
TRACE("Move to: (%d,%d)", col, row); plcd->setCursor(col, row);
_lcd_setcursor(col, row);
} }
// return < 0 on error // return < 0 on error
// return the advanced cols // return the advanced cols
int lcd_put_wchar_max(wchar_t c, pixel_len_t max_length) { int lcd_put_wchar_max(wchar_t c, pixel_len_t max_length) {
// find the HD44780 internal ROM first // find the HD44780 internal ROM first
int ret; int ret;
size_t idx = 0; size_t idx = 0;
hd44780_charmap_t pinval; hd44780_charmap_t pinval;
hd44780_charmap_t localval;
hd44780_charmap_t *copy_address = NULL; hd44780_charmap_t *copy_address = NULL;
pinval.uchar = c; pinval.uchar = c;
pinval.idx = -1; pinval.idx = -1;
@ -1006,37 +979,33 @@ int lcd_put_wchar_max(wchar_t c, pixel_len_t max_length) {
// TODO: fix the '\\' that doesnt exist in the HD44870 // TODO: fix the '\\' that doesnt exist in the HD44870
if (c < 128) { if (c < 128) {
//TRACE("draw char: regular %d", (int)c); plcd->write((uint8_t)c);
_lcd_write((uint8_t)c);
return 1; return 1;
} }
copy_address = NULL; copy_address = NULL;
ret = pf_bsearch_r((void *)g_hd44780_charmap_device, NUM_ARRAY(g_hd44780_charmap_device), pf_bsearch_cb_comp_hd4map_pgm, (void *)&pinval, &idx); ret = pf_bsearch_r((void *)g_hd44780_charmap_device, NUM_ARRAY(g_hd44780_charmap_device), pf_bsearch_cb_comp_hd4map_pgm, (void *)&pinval, &idx);
if (ret >= 0) { if (ret >= 0) {
copy_address = (hd44780_charmap_t *)(g_hd44780_charmap_device + idx); copy_address = (hd44780_charmap_t *)(g_hd44780_charmap_device + idx);
} else {
ret = pf_bsearch_r((void *)g_hd44780_charmap_common, NUM_ARRAY(g_hd44780_charmap_common), pf_bsearch_cb_comp_hd4map_pgm, (void *)&pinval, &idx);
if (ret >= 0) {
copy_address = (hd44780_charmap_t *)(g_hd44780_charmap_common + idx);
} }
else {
ret = pf_bsearch_r((void *)g_hd44780_charmap_common, NUM_ARRAY(g_hd44780_charmap_common), pf_bsearch_cb_comp_hd4map_pgm, (void *)&pinval, &idx);
if (ret >= 0) copy_address = (hd44780_charmap_t *)(g_hd44780_charmap_common + idx);
} }
if (ret >= 0) { if (ret >= 0) {
hd44780_charmap_t localval;
// found // found
FU_ASSERT(NULL != copy_address);
memcpy_P(&localval, copy_address, sizeof(localval)); memcpy_P(&localval, copy_address, sizeof(localval));
FU_ASSERT((localval.uchar == c) && (localval.uchar == pinval.uchar)); plcd->write(localval.idx);
TRACE("draw char: %" PRIu32 "(0x%" PRIX32 ") at ROM %d(+%d)", c, c, (int)localval.idx, (int)localval.idx2);
_lcd_write(localval.idx);
if (max_length >= 2 && localval.idx2 > 0) { if (max_length >= 2 && localval.idx2 > 0) {
_lcd_write(localval.idx2); plcd->write(localval.idx2);
return 2; return 2;
} }
return 1; return 1;
} }
// print '?' instead
TRACE("draw char: Not found " PRIu32 "(0x%" PRIX32 ")", c, c); // Not found, print '?' instead
_lcd_write((uint8_t)'?'); plcd->write((uint8_t)'?');
return 1; return 1;
} }
@ -1044,7 +1013,6 @@ int lcd_put_wchar_max(wchar_t c, pixel_len_t max_length) {
* @brief Draw a UTF-8 string * @brief Draw a UTF-8 string
* *
* @param utf8_str : the UTF-8 string * @param utf8_str : the UTF-8 string
* @param len : the byte length of the string (returned by strlen(utf8_str) or strlen_P(utf8_str) )
* @param cb_read_byte : the callback function to read one byte from the utf8_str (from RAM or ROM) * @param cb_read_byte : the callback function to read one byte from the utf8_str (from RAM or ROM)
* @param max_length : the pixel length of the string allowed (or number of slots in HD44780) * @param max_length : the pixel length of the string allowed (or number of slots in HD44780)
* *
@ -1052,39 +1020,24 @@ int lcd_put_wchar_max(wchar_t c, pixel_len_t max_length) {
* *
* Draw a UTF-8 string * Draw a UTF-8 string
*/ */
static int lcd_put_u8str_max_cb(const char * utf8_str, uint16_t len, uint8_t (*cb_read_byte)(uint8_t * str), pixel_len_t max_length) { static int lcd_put_u8str_max_cb(const char * utf8_str, uint8_t (*cb_read_byte)(uint8_t * str), pixel_len_t max_length) {
wchar_t ch;
uint8_t *p, *pend;
pixel_len_t ret = 0; pixel_len_t ret = 0;
uint8_t *p = (uint8_t *)utf8_str;
TRACE("BEGIN lcd_put_u8str_max_cb(len=%d, maxlen=%d)", len, max_length); while (ret < max_length) {
pend = (uint8_t *)utf8_str + len; wchar_t ch = 0;
for (p = (uint8_t *)utf8_str; (p < pend) && (ret < max_length); ) {
ch = 0;
p = get_utf8_value_cb(p, cb_read_byte, &ch); p = get_utf8_value_cb(p, cb_read_byte, &ch);
if (NULL == p) { if (!p) break;
TRACE("No more char, break ...");
break;
}
FU_ASSERT(ret < max_length);
ret += lcd_put_wchar_max(ch, max_length - ret); ret += lcd_put_wchar_max(ch, max_length - ret);
} }
return (int)ret; return (int)ret;
} }
int lcd_put_u8str_max(const char * utf8_str, pixel_len_t max_length) { int lcd_put_u8str_max(const char * utf8_str, pixel_len_t max_length) {
//TRACE("BEGIN lcd_put_u8str_max(str='%s', len=%d, maxlen=%d)", utf8_str, strlen(utf8_str), max_length); return lcd_put_u8str_max_cb(utf8_str, read_byte_ram, max_length);
TRACE("BEGIN lcd_put_u8str_max(str='%s')", utf8_str);
TRACE("BEGIN lcd_put_u8str_max('len=%d)", strlen(utf8_str));
TRACE("BEGIN lcd_put_u8str_max(maxlen=%d)", max_length);
return lcd_put_u8str_max_cb(utf8_str, strlen(utf8_str), read_byte_ram, max_length);
} }
int lcd_put_u8str_max_rom(const char * utf8_str_P, pixel_len_t max_length) { int lcd_put_u8str_max_P(const char * utf8_str_P, pixel_len_t max_length) {
//TRACE("BEGIN lcd_put_u8str_max_rom('%s', len=%d, maxlen=%d)", utf8_str_P, strlen_P(utf8_str_P), max_length); return lcd_put_u8str_max_cb(utf8_str_P, read_byte_rom, max_length);
TRACE("BEGIN lcd_put_u8str_max_rom(len=%d)", strlen_P(utf8_str_P));
TRACE("BEGIN lcd_put_u8str_max_rom(maxlen=%d)", max_length);
return lcd_put_u8str_max_cb(utf8_str_P, strlen_P(utf8_str_P), read_byte_rom, max_length);
} }
#endif // DOGLCD #endif // DOGLCD

View file

@ -25,25 +25,22 @@ extern U8GLIB *pu8g;
int lcd_glyph_height(void) { int lcd_glyph_height(void) {
return u8g_GetFontBBXHeight(pu8g->getU8g()); return u8g_GetFontBBXHeight(pu8g->getU8g());
//return u8g_GetFontBBXOffY(pu8g->getU8g());
} }
void lcd_moveto(int col, int row) { void lcd_moveto(int col, int row) {
TRACE("Move to: (%d,%d)", col, row);
_lcd_setcursor(col, row); _lcd_setcursor(col, row);
} }
// return < 0 on error
// return the advanced pixels
int lcd_put_wchar_max(wchar_t c, pixel_len_t max_length) { int lcd_put_wchar_max(wchar_t c, pixel_len_t max_length) {
if (c < 256) { if (c < 256) {
TRACE("draw char: regular %d", (int)c);
_lcd_write((char)c); _lcd_write((char)c);
return u8g_GetFontBBXWidth(pu8g->getU8g()); return u8g_GetFontBBXWidth(pu8g->getU8g());
} }
unsigned int x = pu8g->getPrintCol(), unsigned int x = pu8g->getPrintCol(),
y = pu8g->getPrintRow(), y = pu8g->getPrintRow(),
ret = uxg_DrawWchar(pu8g->getU8g(), x, y, c, max_length); ret = uxg_DrawWchar(pu8g->getU8g(), x, y, c, max_length);
TRACE("uxg_DrawWchar(x=%d,y=%d,maxlen=%d", x, y, max_length);
TRACE("u8g->setPrintPos(x=%d + ret=%d,y=%d", x, ret, y);
pu8g->setPrintPos(x + ret, y); pu8g->setPrintPos(x + ret, y);
return ret; return ret;
@ -53,25 +50,16 @@ int lcd_put_u8str_max(const char * utf8_str, pixel_len_t max_length) {
unsigned int x = pu8g->getPrintCol(), unsigned int x = pu8g->getPrintCol(),
y = pu8g->getPrintRow(), y = pu8g->getPrintRow(),
ret = uxg_DrawUtf8Str(pu8g->getU8g(), x, y, utf8_str, max_length); ret = uxg_DrawUtf8Str(pu8g->getU8g(), x, y, utf8_str, max_length);
TRACE("uxg_DrawUtf8Str(x=%d,y=%d,maxlen=%d", x, y, max_length);
TRACE("u8g->setPrintPos(x=%d + ret=%d,y=%d", x, ret, y);
pu8g->setPrintPos(x + ret, y); pu8g->setPrintPos(x + ret, y);
return ret; return ret;
} }
int lcd_put_u8str_max_rom(const char * utf8_str_P, pixel_len_t max_length) { int lcd_put_u8str_max_P(const char * utf8_str_P, pixel_len_t max_length) {
unsigned int x = pu8g->getPrintCol(), unsigned int x = pu8g->getPrintCol(),
y = pu8g->getPrintRow(), y = pu8g->getPrintRow(),
ret = uxg_DrawUtf8StrP(pu8g->getU8g(), x, y, utf8_str_P, max_length); ret = uxg_DrawUtf8StrP(pu8g->getU8g(), x, y, utf8_str_P, max_length);
TRACE("uxg_DrawUtf8StrP(x=%d,y=%d,maxlen=%d", x, y, max_length);
TRACE("u8g->setPrintPos(x=%d + ret=%d,y=%d", x, ret, y);
pu8g->setPrintPos(x + ret, y); pu8g->setPrintPos(x + ret, y);
return ret; return ret;
} }
#else // !DOGLCD #endif // DOGLCD
#define _lcd_write(a) TRACE("Write LCD: %c (%d)", (a), (int)(a));
#define _lcd_setcursor(col, row) TRACE("Set cursor LCD: (%d,%d)", (col), (row));
#endif // !DOGLCD

View file

@ -18,28 +18,6 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
typedef void font_t; typedef void font_t;
#ifndef PSTR
#define PSTR(a) a
void* memcpy_from_rom(void *dest, const void * rom_src, size_t sz) {
uint8_t * p;
uint8_t * s;
FU_ASSERT(NULL != dest);
p = (uint8_t*)dest;
s = (uint8_t*)rom_src;
uint8_t c;
while ((p - (uint8_t *)dest) < sz) {
*p = pgm_read_byte(s);
p ++;
s ++;
}
return p;
}
#else
#define memcpy_from_rom memcpy_P
#endif
/** /**
* @brief the callback function to draw something * @brief the callback function to draw something
* *
@ -53,25 +31,14 @@ void* memcpy_from_rom(void *dest, const void * rom_src, size_t sz) {
*/ */
typedef int (* fontgroup_cb_draw_t)(void *userdata, const font_t *fnt_current, const char *msg); typedef int (* fontgroup_cb_draw_t)(void *userdata, const font_t *fnt_current, const char *msg);
//extern int fontgroup_init(font_group_t * root, const uxg_fontinfo_t * fntinfo, int number);
//extern int fontgroup_drawstring(font_group_t *group, const font_t *fnt_default, const char *utf8_msg, void *userdata, fontgroup_cb_draw_t cb_draw);
//extern uxg_fontinfo_t* fontgroup_first(font_group_t * root);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/* return v1 - v2 */ /* return v1 - v2 */
static int fontinfo_compare(uxg_fontinfo_t * v1, uxg_fontinfo_t * v2) { static int fontinfo_compare(uxg_fontinfo_t * v1, uxg_fontinfo_t * v2) {
FU_ASSERT(NULL != v1); if (v1->page < v2->page) return -1;
FU_ASSERT(NULL != v2); else if (v1->page > v2->page) return 1;
if (v1->page < v2->page)
return -1;
else if (v1->page > v2->page)
return 1;
if (v1->end < v2->begin) if (v1->end < v2->begin) return -1;
return -1; else if (v1->begin > v2->end) return 1;
else if (v1->begin > v2->end)
return 1;
return 0; return 0;
} }
@ -80,7 +47,7 @@ static int fontinfo_compare(uxg_fontinfo_t * v1, uxg_fontinfo_t * v2) {
static int pf_bsearch_cb_comp_fntifo_pgm (void *userdata, size_t idx, void *data_pin) { static int pf_bsearch_cb_comp_fntifo_pgm (void *userdata, size_t idx, void *data_pin) {
uxg_fontinfo_t *fntinfo = (uxg_fontinfo_t*)userdata; uxg_fontinfo_t *fntinfo = (uxg_fontinfo_t*)userdata;
uxg_fontinfo_t localval; uxg_fontinfo_t localval;
memcpy_from_rom(&localval, fntinfo + idx, sizeof(localval)); memcpy_P(&localval, fntinfo + idx, sizeof(localval));
return fontinfo_compare(&localval, (uxg_fontinfo_t*)data_pin); return fontinfo_compare(&localval, (uxg_fontinfo_t*)data_pin);
} }
@ -92,7 +59,6 @@ typedef struct _font_group_t {
static int fontgroup_init(font_group_t * root, const uxg_fontinfo_t * fntinfo, int number) { static int fontgroup_init(font_group_t * root, const uxg_fontinfo_t * fntinfo, int number) {
root->m_fntifo = fntinfo; root->m_fntifo = fntinfo;
root->m_fntinfo_num = number; root->m_fntinfo_num = number;
return 0; return 0;
} }
@ -105,26 +71,23 @@ static const font_t* fontgroup_find(font_group_t * root, wchar_t val) {
if (pf_bsearch_r((void*)root->m_fntifo, root->m_fntinfo_num, pf_bsearch_cb_comp_fntifo_pgm, (void*)&vcmp, &idx) < 0) if (pf_bsearch_r((void*)root->m_fntifo, root->m_fntinfo_num, pf_bsearch_cb_comp_fntifo_pgm, (void*)&vcmp, &idx) < 0)
return NULL; return NULL;
memcpy_from_rom(&vcmp, root->m_fntifo + idx, sizeof(vcmp)); memcpy_P(&vcmp, root->m_fntifo + idx, sizeof(vcmp));
return vcmp.fntdata; return vcmp.fntdata;
} }
static void fontgroup_drawwchar(font_group_t *group, const font_t *fnt_default, wchar_t val, void * userdata, fontgroup_cb_draw_t cb_draw_ram) { static void fontgroup_drawwchar(font_group_t *group, const font_t *fnt_default, wchar_t val, void * userdata, fontgroup_cb_draw_t cb_draw_ram) {
uint8_t buf[2] = {0, 0}; uint8_t buf[2] = {0, 0};
const font_t * fntpqm = NULL; const font_t * fntpqm = (font_t*)fontgroup_find(group, val);
if (!fntpqm) {
TRACE("fontgroup_drawwchar char=%d(0x%X)", (int)val, (int)val); // Unknown char, use default font
fntpqm = (font_t*)fontgroup_find(group, val);
if (NULL == fntpqm) {
buf[0] = (uint8_t)(val & 0xFF); buf[0] = (uint8_t)(val & 0xFF);
fntpqm = fnt_default; fntpqm = fnt_default;
TRACE("Unknown char %d(0x%X), use default font", (int)val, (int)val);
} }
if (fnt_default != fntpqm) { if (fnt_default != fntpqm) {
buf[0] = (uint8_t)(val & 0x7F); buf[0] = (uint8_t)(val & 0x7F);
buf[0] |= 0x80; // use upper page to avoid 0x00 error in C. you may want to generate the font data buf[0] |= 0x80; // use upper page to avoid 0x00 error in C. you may want to generate the font data
} }
//TRACE("set font: %p; (default=%p)", fntpqm, UXG_DEFAULT_FONT);
cb_draw_ram (userdata, fntpqm, (char*) buf); cb_draw_ram (userdata, fntpqm, (char*) buf);
} }
@ -142,31 +105,27 @@ static void fontgroup_drawwchar(font_group_t *group, const font_t *fnt_default,
* *
* Get the screen pixel width of a ROM UTF-8 string * Get the screen pixel width of a ROM UTF-8 string
*/ */
static void fontgroup_drawstring(font_group_t *group, const font_t *fnt_default, const char *utf8_msg, int len_msg, read_byte_cb_t cb_read_byte, void * userdata, fontgroup_cb_draw_t cb_draw_ram) { static void fontgroup_drawstring(font_group_t *group, const font_t *fnt_default, const char *utf8_msg, read_byte_cb_t cb_read_byte, void * userdata, fontgroup_cb_draw_t cb_draw_ram) {
uint8_t *pend = (uint8_t*)utf8_msg + len_msg; uint8_t *p = (uint8_t*)utf8_msg;
for (uint8_t *p = (uint8_t*)utf8_msg; p < pend; ) { for (;;) {
wchar_t val = 0; wchar_t val = 0;
p = get_utf8_value_cb(p, cb_read_byte, &val); p = get_utf8_value_cb(p, cb_read_byte, &val);
if (NULL == p) { if (!val) break;
TRACE("No more char, break ...");
break;
}
fontgroup_drawwchar(group, fnt_default, val, userdata, cb_draw_ram); fontgroup_drawwchar(group, fnt_default, val, userdata, cb_draw_ram);
} }
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
static char flag_fontgroup_inited1 = 0; static bool flag_fontgroup_was_inited = false;
#define flag_fontgroup_inited flag_fontgroup_inited1
static font_group_t g_fontgroup_root = {NULL, 0}; static font_group_t g_fontgroup_root = {NULL, 0};
/** /**
* @brief check if font is loaded * @brief check if font is loaded
*/ */
char uxg_Utf8FontIsInited(void) { return flag_fontgroup_inited; } static inline bool uxg_Utf8FontIsInited(void) { return flag_fontgroup_was_inited; }
int uxg_SetUtf8Fonts (const uxg_fontinfo_t * fntinfo, int number) { int uxg_SetUtf8Fonts (const uxg_fontinfo_t * fntinfo, int number) {
flag_fontgroup_inited = 1; flag_fontgroup_was_inited = 1;
return fontgroup_init(&g_fontgroup_root, fntinfo, number); return fontgroup_init(&g_fontgroup_root, fntinfo, number);
} }
@ -179,22 +138,17 @@ struct _uxg_drawu8_data_t {
const void * fnt_prev; const void * fnt_prev;
}; };
static int fontgroup_cb_draw_u8g (void *userdata, const font_t *fnt_current, const char *msg) { static int fontgroup_cb_draw_u8g(void *userdata, const font_t *fnt_current, const char *msg) {
struct _uxg_drawu8_data_t * pdata = (_uxg_drawu8_data_t*)userdata; struct _uxg_drawu8_data_t * pdata = (_uxg_drawu8_data_t*)userdata;
FU_ASSERT(NULL != userdata);
if (pdata->fnt_prev != fnt_current) { if (pdata->fnt_prev != fnt_current) {
u8g_SetFont(pdata->pu8g, (const u8g_fntpgm_uint8_t*)fnt_current); u8g_SetFont(pdata->pu8g, (const u8g_fntpgm_uint8_t*)fnt_current);
//u8g_SetFontPosBottom(pdata->pu8g); //u8g_SetFontPosBottom(pdata->pu8g);
pdata->fnt_prev = fnt_current; pdata->fnt_prev = fnt_current;
} }
if ((pdata->max_width != PIXEL_LEN_NOLIMIT) && (pdata->adv + u8g_GetStrPixelWidth(pdata->pu8g, (char*)msg) > pdata->max_width)) { if ((pdata->max_width != PIXEL_LEN_NOLIMIT) && (pdata->adv + u8g_GetStrPixelWidth(pdata->pu8g, (char*)msg) > pdata->max_width))
TRACE("return end, adv=%d, width=%d, maxlen=%d", pdata->adv, u8g_GetStrPixelWidth(pdata->pu8g, (char*)msg), pdata->max_width);
return 1; return 1;
}
TRACE("Draw string 0x%X", (int)msg[0]);
pdata->adv += u8g_DrawStr(pdata->pu8g, pdata->x + pdata->adv, pdata->y, (char*) msg); pdata->adv += u8g_DrawStr(pdata->pu8g, pdata->x + pdata->adv, pdata->y, (char*) msg);
//TRACE("adv pos= %d", pdata->adv);
return 0; return 0;
} }
@ -260,7 +214,7 @@ unsigned int uxg_DrawUtf8Str(u8g_t *pu8g, unsigned int x, unsigned int y, const
data.adv = 0; data.adv = 0;
data.max_width = max_width; data.max_width = max_width;
data.fnt_prev = NULL; data.fnt_prev = NULL;
fontgroup_drawstring(group, fnt_default, utf8_msg, strlen(utf8_msg), read_byte_ram, (void*)&data, fontgroup_cb_draw_u8g); fontgroup_drawstring(group, fnt_default, utf8_msg, read_byte_ram, (void*)&data, fontgroup_cb_draw_u8g);
u8g_SetFont(pu8g, (const u8g_fntpgm_uint8_t*)fnt_default); u8g_SetFont(pu8g, (const u8g_fntpgm_uint8_t*)fnt_default);
return data.adv; return data.adv;
@ -285,7 +239,6 @@ unsigned int uxg_DrawUtf8StrP(u8g_t *pu8g, unsigned int x, unsigned int y, const
const font_t *fnt_default = uxg_GetFont(pu8g); const font_t *fnt_default = uxg_GetFont(pu8g);
if (!uxg_Utf8FontIsInited()) { if (!uxg_Utf8FontIsInited()) {
TRACE("Error, utf8string not inited!");
u8g_DrawStrP(pu8g, x, y, (const u8g_pgm_uint8_t *)PSTR("Err: utf8 font not initialized.")); u8g_DrawStrP(pu8g, x, y, (const u8g_pgm_uint8_t *)PSTR("Err: utf8 font not initialized."));
return 0; return 0;
} }
@ -295,19 +248,15 @@ unsigned int uxg_DrawUtf8StrP(u8g_t *pu8g, unsigned int x, unsigned int y, const
data.adv = 0; data.adv = 0;
data.max_width = max_width; data.max_width = max_width;
data.fnt_prev = NULL; data.fnt_prev = NULL;
TRACE("call fontgroup_drawstring"); fontgroup_drawstring(group, fnt_default, utf8_msg, read_byte_rom, (void*)&data, fontgroup_cb_draw_u8g);
fontgroup_drawstring(group, fnt_default, utf8_msg, my_strlen_P(utf8_msg), read_byte_rom, (void*)&data, fontgroup_cb_draw_u8g);
TRACE("restore font");
u8g_SetFont(pu8g, (const u8g_fntpgm_uint8_t*)fnt_default); u8g_SetFont(pu8g, (const u8g_fntpgm_uint8_t*)fnt_default);
TRACE("return %d", data.adv);
return data.adv; return data.adv;
} }
static int fontgroup_cb_draw_u8gstrlen(void *userdata, const font_t *fnt_current, const char *msg) { static int fontgroup_cb_draw_u8gstrlen(void *userdata, const font_t *fnt_current, const char *msg) {
struct _uxg_drawu8_data_t * pdata = (_uxg_drawu8_data_t*)userdata; struct _uxg_drawu8_data_t * pdata = (_uxg_drawu8_data_t*)userdata;
FU_ASSERT(NULL != userdata);
if (pdata->fnt_prev != fnt_current) { if (pdata->fnt_prev != fnt_current) {
u8g_SetFont(pdata->pu8g, (const u8g_fntpgm_uint8_t*)fnt_current); u8g_SetFont(pdata->pu8g, (const u8g_fntpgm_uint8_t*)fnt_current);
u8g_SetFontPosBottom(pdata->pu8g); u8g_SetFontPosBottom(pdata->pu8g);
@ -332,15 +281,12 @@ int uxg_GetUtf8StrPixelWidth(u8g_t *pu8g, const char *utf8_msg) {
font_group_t *group = &g_fontgroup_root; font_group_t *group = &g_fontgroup_root;
const font_t *fnt_default = uxg_GetFont(pu8g); const font_t *fnt_default = uxg_GetFont(pu8g);
if (!uxg_Utf8FontIsInited()) { if (!uxg_Utf8FontIsInited()) return -1;
TRACE("Err: utf8 font not initialized.");
return -1;
}
memset(&data, 0, sizeof(data)); memset(&data, 0, sizeof(data));
data.pu8g = pu8g; data.pu8g = pu8g;
data.adv = 0; data.adv = 0;
fontgroup_drawstring(group, fnt_default, utf8_msg, strlen(utf8_msg), read_byte_ram, (void*)&data, fontgroup_cb_draw_u8gstrlen); fontgroup_drawstring(group, fnt_default, utf8_msg, read_byte_ram, (void*)&data, fontgroup_cb_draw_u8gstrlen);
u8g_SetFont(pu8g, (const u8g_fntpgm_uint8_t*)fnt_default); u8g_SetFont(pu8g, (const u8g_fntpgm_uint8_t*)fnt_default);
return data.adv; return data.adv;
@ -361,14 +307,12 @@ int uxg_GetUtf8StrPixelWidthP(u8g_t *pu8g, const char *utf8_msg) {
font_group_t *group = &g_fontgroup_root; font_group_t *group = &g_fontgroup_root;
const font_t *fnt_default = uxg_GetFont(pu8g); const font_t *fnt_default = uxg_GetFont(pu8g);
if (!uxg_Utf8FontIsInited()) { if (!uxg_Utf8FontIsInited()) return -1;
TRACE("Err: utf8 font not initialized.");
return -1;
}
memset(&data, 0, sizeof(data)); memset(&data, 0, sizeof(data));
data.pu8g = pu8g; data.pu8g = pu8g;
data.adv = 0; data.adv = 0;
fontgroup_drawstring(group, fnt_default, utf8_msg, my_strlen_P(utf8_msg), read_byte_rom, (void*)&data, fontgroup_cb_draw_u8gstrlen); fontgroup_drawstring(group, fnt_default, utf8_msg, read_byte_rom, (void*)&data, fontgroup_cb_draw_u8gstrlen);
u8g_SetFont(pu8g, (const u8g_fntpgm_uint8_t*)fnt_default); u8g_SetFont(pu8g, (const u8g_fntpgm_uint8_t*)fnt_default);
return data.adv; return data.adv;
} }

View file

@ -12,11 +12,6 @@
#include <U8glib.h> #include <U8glib.h>
#include "fontutils.h" #include "fontutils.h"
#ifdef __cplusplus
extern "C" {
#endif
// the macro to indicate a UTF-8 string // the macro to indicate a UTF-8 string
// You should to save the C/C++ source in UTF-8 encoding! // You should to save the C/C++ source in UTF-8 encoding!
// Once you change your UTF-8 strings, you need to call the script uxggenpages.sh to create the font data file fontutf8-data.h // Once you change your UTF-8 strings, you need to call the script uxggenpages.sh to create the font data file fontutf8-data.h
@ -30,21 +25,16 @@ typedef struct _uxg_fontinfo_t {
const u8g_fntpgm_uint8_t *fntdata; const u8g_fntpgm_uint8_t *fntdata;
} uxg_fontinfo_t; } uxg_fontinfo_t;
extern int uxg_SetUtf8Fonts (const uxg_fontinfo_t * fntinfo, int number); // fntinfo is type of PROGMEM int uxg_SetUtf8Fonts (const uxg_fontinfo_t * fntinfo, int number); // fntinfo is type of PROGMEM
extern char uxg_Utf8FontIsInited(void);
extern unsigned int uxg_DrawWchar (u8g_t *pu8g, unsigned int x, unsigned int y, wchar_t ch, pixel_len_t max_length); unsigned int uxg_DrawWchar (u8g_t *pu8g, unsigned int x, unsigned int y, wchar_t ch, pixel_len_t max_length);
extern unsigned int uxg_DrawUtf8Str (u8g_t *pu8g, unsigned int x, unsigned int y, const char *utf8_msg, pixel_len_t max_length); unsigned int uxg_DrawUtf8Str (u8g_t *pu8g, unsigned int x, unsigned int y, const char *utf8_msg, pixel_len_t max_length);
extern unsigned int uxg_DrawUtf8StrP (u8g_t *pu8g, unsigned int x, unsigned int y, const char *utf8_msg, pixel_len_t max_length); unsigned int uxg_DrawUtf8StrP (u8g_t *pu8g, unsigned int x, unsigned int y, const char *utf8_msg, pixel_len_t max_length);
extern int uxg_GetUtf8StrPixelWidth(u8g_t *pu8g, const char *utf8_msg); int uxg_GetUtf8StrPixelWidth(u8g_t *pu8g, const char *utf8_msg);
extern int uxg_GetUtf8StrPixelWidthP(u8g_t *pu8g, const char *utf8_msg); int uxg_GetUtf8StrPixelWidthP(u8g_t *pu8g, const char *utf8_msg);
#define uxg_GetFont(puxg) ((puxg)->font) #define uxg_GetFont(puxg) ((puxg)->font)
#ifdef __cplusplus
}
#endif
#endif // _UXG_FONTUTF8_H #endif // _UXG_FONTUTF8_H

View file

@ -80,7 +80,7 @@
#else #else
#define MAX_MESSAGE_LENGTH CHARSIZE * 2 * (LCD_WIDTH) #define MAX_MESSAGE_LENGTH CHARSIZE * 2 * (LCD_WIDTH)
#endif #endif
uint8_t status_scroll_pos = 0; uint8_t status_scroll_offset = 0;
#else #else
#define MAX_MESSAGE_LENGTH CHARSIZE * (LCD_WIDTH) #define MAX_MESSAGE_LENGTH CHARSIZE * (LCD_WIDTH)
#endif #endif
@ -5360,30 +5360,8 @@ void lcd_update() {
} // ELAPSED(ms, next_lcd_update_ms) } // ELAPSED(ms, next_lcd_update_ms)
} }
inline void pad_message_string() {
uint8_t i = 0, j = 0;
char c;
lcd_status_message[MAX_MESSAGE_LENGTH] = '\0';
while ((c = lcd_status_message[i]) && j < LCD_WIDTH) {
if (PRINTABLE(c)) j++;
i++;
}
if (true
#if ENABLED(STATUS_MESSAGE_SCROLLING)
&& j < LCD_WIDTH
#endif
) {
// pad with spaces to fill up the line
while (j++ < LCD_WIDTH) lcd_status_message[i++] = ' ';
// chop off at the edge
lcd_status_message[i] = '\0';
}
}
void lcd_finishstatus(const bool persist=false) { void lcd_finishstatus(const bool persist=false) {
pad_message_string();
#if !(ENABLED(LCD_PROGRESS_BAR) && (PROGRESS_MSG_EXPIRE > 0)) #if !(ENABLED(LCD_PROGRESS_BAR) && (PROGRESS_MSG_EXPIRE > 0))
UNUSED(persist); UNUSED(persist);
#endif #endif
@ -5401,7 +5379,7 @@ void lcd_finishstatus(const bool persist=false) {
#endif #endif
#if ENABLED(STATUS_MESSAGE_SCROLLING) #if ENABLED(STATUS_MESSAGE_SCROLLING)
status_scroll_pos = 0; status_scroll_offset = 0;
#endif #endif
} }
@ -5413,7 +5391,26 @@ bool lcd_hasstatus() { return (lcd_status_message[0] != '\0'); }
void lcd_setstatus(const char * const message, const bool persist) { void lcd_setstatus(const char * const message, const bool persist) {
if (lcd_status_message_level > 0) return; if (lcd_status_message_level > 0) return;
strncpy(lcd_status_message, message, MAX_MESSAGE_LENGTH);
// Here we have a problem. The message is encoded in UTF8, so
// arbitrarily cutting it will be a problem. We MUST be sure
// that there is no cutting in the middle of a multibyte character!
// Get a pointer to the null terminator
const char* pend = message + strlen(message);
// If length of supplied UTF8 string is greater than
// our buffer size, start cutting whole UTF8 chars
while ((pend - message) > MAX_MESSAGE_LENGTH) {
--pend;
while (!START_OF_UTF8_CHAR(*pend)) --pend;
};
// At this point, we have the proper cut point. Use it
uint8_t maxLen = pend - message;
strncpy(lcd_status_message, message, maxLen);
lcd_status_message[maxLen] = '\0';
lcd_finishstatus(persist); lcd_finishstatus(persist);
} }
@ -5421,7 +5418,26 @@ void lcd_setstatusPGM(const char * const message, int8_t level) {
if (level < 0) level = lcd_status_message_level = 0; if (level < 0) level = lcd_status_message_level = 0;
if (level < lcd_status_message_level) return; if (level < lcd_status_message_level) return;
lcd_status_message_level = level; lcd_status_message_level = level;
strncpy_P(lcd_status_message, message, MAX_MESSAGE_LENGTH);
// Here we have a problem. The message is encoded in UTF8, so
// arbitrarily cutting it will be a problem. We MUST be sure
// that there is no cutting in the middle of a multibyte character!
// Get a pointer to the null terminator
const char* pend = message + strlen_P(message);
// If length of supplied UTF8 string is greater than
// our buffer size, start cutting whole UTF8 chars
while ((pend - message) > MAX_MESSAGE_LENGTH) {
--pend;
while (!START_OF_UTF8_CHAR(pgm_read_byte(pend))) --pend;
};
// At this point, we have the proper cut point. Use it
uint8_t maxLen = pend - message;
strncpy_P(lcd_status_message, message, maxLen);
lcd_status_message[maxLen] = '\0';
lcd_finishstatus(level > 0); lcd_finishstatus(level > 0);
} }

View file

@ -341,9 +341,9 @@ void lcd_kill_screen() {
lcd_moveto(0, h4 * 1); lcd_moveto(0, h4 * 1);
lcd_put_u8str(lcd_status_message); lcd_put_u8str(lcd_status_message);
lcd_moveto(0, h4 * 2); lcd_moveto(0, h4 * 2);
lcd_put_u8str_rom(PSTR(MSG_HALTED)); lcd_put_u8str_P(PSTR(MSG_HALTED));
lcd_moveto(0, h4 * 3); lcd_moveto(0, h4 * 3);
lcd_put_u8str_rom(PSTR(MSG_PLEASE_RESET)); lcd_put_u8str_P(PSTR(MSG_PLEASE_RESET));
} while (u8g.nextPage()); } while (u8g.nextPage());
} }
@ -415,7 +415,7 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop
int8_t pad = (LCD_WIDTH - utf8_strlen_P(pstr)) / 2; int8_t pad = (LCD_WIDTH - utf8_strlen_P(pstr)) / 2;
while (--pad >= 0) { lcd_put_wchar(' '); n--; } while (--pad >= 0) { lcd_put_wchar(' '); n--; }
} }
n -= lcd_put_u8str_max_rom(pstr, n); n -= lcd_put_u8str_max_P(pstr, n);
if (NULL != valstr) { if (NULL != valstr) {
n -= lcd_put_u8str_max(valstr, n); n -= lcd_put_u8str_max(valstr, n);
} }
@ -431,7 +431,7 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop
if (lcd_implementation_mark_as_selected(row, isSelected)) { if (lcd_implementation_mark_as_selected(row, isSelected)) {
uint8_t n = LCD_WIDTH - (START_COL) - 2; uint8_t n = LCD_WIDTH - (START_COL) - 2;
n *= DOG_CHAR_WIDTH; n *= DOG_CHAR_WIDTH;
n -= lcd_put_u8str_max_rom(pstr, n); n -= lcd_put_u8str_max_P(pstr, n);
while (n - DOG_CHAR_WIDTH > 0) { n -= lcd_put_wchar(' '); } while (n - DOG_CHAR_WIDTH > 0) { n -= lcd_put_wchar(' '); }
lcd_moveto(LCD_PIXEL_WIDTH - (DOG_CHAR_WIDTH), row_y2); lcd_moveto(LCD_PIXEL_WIDTH - (DOG_CHAR_WIDTH), row_y2);
lcd_put_wchar(post_char); lcd_put_wchar(post_char);
@ -451,11 +451,11 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop
const uint8_t vallen = (pgm ? utf8_strlen_P(data) : utf8_strlen((char*)data)); const uint8_t vallen = (pgm ? utf8_strlen_P(data) : utf8_strlen((char*)data));
uint8_t n = LCD_WIDTH - (START_COL) - 2 - vallen; uint8_t n = LCD_WIDTH - (START_COL) - 2 - vallen;
n *= DOG_CHAR_WIDTH; n *= DOG_CHAR_WIDTH;
n -= lcd_put_u8str_max_rom(pstr, n); n -= lcd_put_u8str_max_P(pstr, n);
lcd_put_wchar(':'); lcd_put_wchar(':');
while (n - DOG_CHAR_WIDTH > 0) { n -= lcd_put_wchar(' '); } while (n - DOG_CHAR_WIDTH > 0) { n -= lcd_put_wchar(' '); }
lcd_moveto(LCD_PIXEL_WIDTH - (DOG_CHAR_WIDTH) * vallen, row_y2); lcd_moveto(LCD_PIXEL_WIDTH - (DOG_CHAR_WIDTH) * vallen, row_y2);
if (pgm) lcd_put_u8str_rom(data); else lcd_put_u8str((char*)data); if (pgm) lcd_put_u8str_P(data); else lcd_put_u8str((char*)data);
} }
} }
@ -499,7 +499,7 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop
bool onpage = PAGE_CONTAINS(baseline + 1 - (DOG_CHAR_HEIGHT_EDIT), baseline); bool onpage = PAGE_CONTAINS(baseline + 1 - (DOG_CHAR_HEIGHT_EDIT), baseline);
if (onpage) { if (onpage) {
lcd_moveto(0, baseline); lcd_moveto(0, baseline);
lcd_put_u8str_rom(pstr); lcd_put_u8str_P(pstr);
} }
if (value != NULL) { if (value != NULL) {
@ -641,7 +641,7 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop
if (!isnan(ubl.z_values[x_plot][y_plot])) if (!isnan(ubl.z_values[x_plot][y_plot]))
lcd_put_u8str(ftostr43sign(ubl.z_values[x_plot][y_plot])); lcd_put_u8str(ftostr43sign(ubl.z_values[x_plot][y_plot]));
else else
lcd_put_u8str_rom(PSTR(" -----")); lcd_put_u8str_P(PSTR(" -----"));
} }
} }

View file

@ -347,26 +347,51 @@ void lcd_implementation_clear() { lcd.clear(); }
} }
// Scroll the PSTR 'text' in a 'len' wide field for 'time' milliseconds at position col,line // Scroll the PSTR 'text' in a 'len' wide field for 'time' milliseconds at position col,line
void lcd_scroll(const int16_t col, const int16_t line, const char* const text, const int16_t len, const int16_t time) { void lcd_scroll(const uint8_t col, const uint8_t line, const char* const text, const uint8_t len, const int16_t time) {
#if 1 uint8_t slen = utf8_strlen_P(text);
lcd_put_u8str(text); if (slen < len) {
#else // Fits into,
char tmp[LCD_WIDTH + 1] = {0};
int16_t n = MAX(utf8_strlen_P(text) - len, 0);
for (int16_t i = 0; i <= n; i++) {
utf8_strncpy_p(tmp, text + i, MIN(len, LCD_WIDTH));
lcd_moveto(col, line); lcd_moveto(col, line);
lcd_put_u8str(tmp); lcd_put_u8str_max_P(text, len);
delay(time / MAX(n, 1)); while (slen < len) {
lcd_put_wchar(' ');
++slen;
}
safe_delay(time);
}
else {
const char* p = text;
int dly = time / MAX(slen, 1);
for (uint8_t i = 0; i <= slen; i++) {
// Go to the correct place
lcd_moveto(col, line);
// Print the text
lcd_put_u8str_max_P(p, len);
// Fill with spaces
uint8_t ix = slen - i;
while (ix < len) {
lcd_put_wchar(' ');
++ix;
}
// Delay
safe_delay(dly);
// Advance to the next UTF8 valid position
p++;
while (!START_OF_UTF8_CHAR(pgm_read_byte(p))) p++;
}
} }
#endif
} }
static void logo_lines(const char* const extra) { static void logo_lines(const char* const extra) {
int16_t indent = (LCD_WIDTH - 8 - utf8_strlen_P(extra)) / 2; int16_t indent = (LCD_WIDTH - 8 - utf8_strlen_P(extra)) / 2;
lcd_moveto(indent, 0); lcd_put_wchar('\x00'); lcd_put_u8str_rom(PSTR( "------" )); lcd_put_wchar('\x01'); lcd_moveto(indent, 0); lcd_put_wchar('\x00'); lcd_put_u8str_P(PSTR( "------" )); lcd_put_wchar('\x01');
lcd_moveto(indent, 1); lcd_put_u8str_rom(PSTR("|Marlin|")); lcd_put_u8str_rom(extra); lcd_moveto(indent, 1); lcd_put_u8str_P(PSTR("|Marlin|")); lcd_put_u8str_P(extra);
lcd_moveto(indent, 2); lcd_put_wchar('\x02'); lcd_put_u8str_rom(PSTR( "------" )); lcd_put_wchar('\x03'); lcd_moveto(indent, 2); lcd_put_wchar('\x02'); lcd_put_u8str_P(PSTR( "------" )); lcd_put_wchar('\x03');
} }
void lcd_bootscreen() { void lcd_bootscreen() {
@ -379,7 +404,7 @@ void lcd_implementation_clear() { lcd.clear(); }
lcd_erase_line(3); \ lcd_erase_line(3); \
if (utf8_strlen(STRING) <= LCD_WIDTH) { \ if (utf8_strlen(STRING) <= LCD_WIDTH) { \
lcd_moveto((LCD_WIDTH - utf8_strlen_P(PSTR(STRING))) / 2, 3); \ lcd_moveto((LCD_WIDTH - utf8_strlen_P(PSTR(STRING))) / 2, 3); \
lcd_put_u8str_rom(PSTR(STRING)); \ lcd_put_u8str_P(PSTR(STRING)); \
safe_delay(DELAY); \ safe_delay(DELAY); \
} \ } \
else { \ else { \
@ -452,10 +477,10 @@ void lcd_kill_screen() {
lcd_moveto(0, 2); lcd_moveto(0, 2);
#else #else
lcd_moveto(0, 2); lcd_moveto(0, 2);
lcd_put_u8str_rom(PSTR(MSG_HALTED)); lcd_put_u8str_P(PSTR(MSG_HALTED));
lcd_moveto(0, 3); lcd_moveto(0, 3);
#endif #endif
lcd_put_u8str_rom(PSTR(MSG_PLEASE_RESET)); lcd_put_u8str_P(PSTR(MSG_PLEASE_RESET));
} }
// //
@ -473,7 +498,7 @@ FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const
else { else {
#if DISABLED(HOME_AFTER_DEACTIVATE) && DISABLED(DISABLE_REDUCED_ACCURACY_WARNING) #if DISABLED(HOME_AFTER_DEACTIVATE) && DISABLED(DISABLE_REDUCED_ACCURACY_WARNING)
if (!axis_known_position[axis]) if (!axis_known_position[axis])
lcd_put_u8str_rom(axis == Z_AXIS ? PSTR(" ") : PSTR(" ")); lcd_put_u8str_P(axis == Z_AXIS ? PSTR(" ") : PSTR(" "));
else else
#endif #endif
lcd_put_u8str(value); lcd_put_u8str(value);
@ -634,11 +659,11 @@ static void lcd_implementation_status_screen() {
#if ENABLED(SDSUPPORT) #if ENABLED(SDSUPPORT)
lcd_moveto(0, 2); lcd_moveto(0, 2);
lcd_put_u8str_rom(PSTR("SD")); lcd_put_u8str_P(PSTR("SD"));
if (IS_SD_PRINTING) if (IS_SD_PRINTING)
lcd_put_u8str(itostr3(card.percentDone())); lcd_put_u8str(itostr3(card.percentDone()));
else else
lcd_put_u8str_rom(PSTR("---")); lcd_put_u8str_P(PSTR("---"));
lcd_put_wchar('%'); lcd_put_wchar('%');
#endif // SDSUPPORT #endif // SDSUPPORT
@ -698,11 +723,11 @@ static void lcd_implementation_status_screen() {
#if LCD_WIDTH >= 20 && ENABLED(SDSUPPORT) #if LCD_WIDTH >= 20 && ENABLED(SDSUPPORT)
lcd_moveto(7, 2); lcd_moveto(7, 2);
lcd_put_u8str_rom(PSTR("SD")); lcd_put_u8str_P(PSTR("SD"));
if (IS_SD_PRINTING) if (IS_SD_PRINTING)
lcd_put_u8str(itostr3(card.percentDone())); lcd_put_u8str(itostr3(card.percentDone()));
else else
lcd_put_u8str_rom(PSTR("---")); lcd_put_u8str_P(PSTR("---"));
lcd_put_wchar('%'); lcd_put_wchar('%');
#endif // LCD_WIDTH >= 20 && SDSUPPORT #endif // LCD_WIDTH >= 20 && SDSUPPORT
@ -739,9 +764,9 @@ static void lcd_implementation_status_screen() {
// Show Filament Diameter and Volumetric Multiplier % // Show Filament Diameter and Volumetric Multiplier %
// After allowing lcd_status_message to show for 5 seconds // After allowing lcd_status_message to show for 5 seconds
if (ELAPSED(millis(), previous_lcd_status_ms + 5000UL)) { if (ELAPSED(millis(), previous_lcd_status_ms + 5000UL)) {
lcd_put_u8str_rom(PSTR("Dia ")); lcd_put_u8str_P(PSTR("Dia "));
lcd_put_u8str(ftostr12ns(filament_width_meas)); lcd_put_u8str(ftostr12ns(filament_width_meas));
lcd_put_u8str_rom(PSTR(" V")); lcd_put_u8str_P(PSTR(" V"));
lcd_put_u8str(itostr3(100.0 * ( lcd_put_u8str(itostr3(100.0 * (
parser.volumetric_enabled parser.volumetric_enabled
? planner.volumetric_area_nominal / planner.volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM] ? planner.volumetric_area_nominal / planner.volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM]
@ -756,35 +781,76 @@ static void lcd_implementation_status_screen() {
#if ENABLED(STATUS_MESSAGE_SCROLLING) #if ENABLED(STATUS_MESSAGE_SCROLLING)
static bool last_blink = false; static bool last_blink = false;
const uint8_t slen = utf8_strlen(lcd_status_message);
const char *stat = lcd_status_message + status_scroll_pos; // Get the UTF8 character count of the string
if (slen <= LCD_WIDTH) uint8_t slen = utf8_strlen(lcd_status_message);
lcd_put_u8str(stat); // The string isn't scrolling
else { // If the string fits into the LCD, just print it and do not scroll it
if (status_scroll_pos <= slen - LCD_WIDTH) if (slen <= LCD_WIDTH) {
lcd_put_u8str(stat); // The string fills the screen
else { // The string isn't scrolling and may not fill the screen
uint8_t chars = LCD_WIDTH; lcd_put_u8str(lcd_status_message);
if (status_scroll_pos < slen) { // First string still visible
lcd_put_u8str(stat); // The string leaves space // Fill the rest with spaces
chars -= slen - status_scroll_pos; // Amount of space left while (slen < LCD_WIDTH) {
lcd_put_wchar(' ');
++slen;
} }
}
else {
// String is larger than the available space in screen.
// Get a pointer to the next valid UTF8 character
const char *stat = lcd_status_message + status_scroll_offset;
// Get the string remaining length
const uint8_t rlen = utf8_strlen(stat);
// If we have enough characters to display
if (rlen >= LCD_WIDTH) {
// The remaining string fills the screen - Print it
lcd_put_u8str_max(stat, LCD_WIDTH);
}
else {
// The remaining string does not completely fill the screen
lcd_put_u8str_max(stat, LCD_WIDTH); // The string leaves space
uint8_t chars = LCD_WIDTH - rlen; // Amount of space left in characters
lcd_put_wchar('.'); // Always at 1+ spaces left, draw a dot lcd_put_wchar('.'); // Always at 1+ spaces left, draw a dot
if (--chars) { if (--chars) { // Draw a second dot if there's space
if (status_scroll_pos < slen + 1) // Draw a second dot if there's space lcd_put_wchar('.');
--chars, lcd_put_wchar('.'); if (--chars)
if (chars) lcd_put_u8str_max(lcd_status_message, chars); // Print a second copy of the message lcd_put_u8str_max(lcd_status_message, chars); // Print a second copy of the message
} }
} }
if (last_blink != blink) { if (last_blink != blink) {
last_blink = blink; last_blink = blink;
// Skip any non-printing bytes
if (status_scroll_pos < slen) while (!PRINTABLE(lcd_status_message[status_scroll_pos])) status_scroll_pos++; // Adjust by complete UTF8 characters
if (++status_scroll_pos >= slen + 2) status_scroll_pos = 0; if (status_scroll_offset < slen) {
status_scroll_offset++;
while (!START_OF_UTF8_CHAR(lcd_status_message[status_scroll_offset]))
status_scroll_offset++;
}
else
status_scroll_offset = 0;
} }
} }
#else #else
lcd_put_u8str(lcd_status_message); UNUSED(blink);
// Get the UTF8 character count of the string
uint8_t slen = utf8_strlen(lcd_status_message);
// Just print the string to the LCD
lcd_put_u8str_max(lcd_status_message, LCD_WIDTH);
// Fill the rest with spaces if there are missing spaces
while (slen < LCD_WIDTH) {
lcd_put_wchar(' ');
++slen;
}
#endif #endif
} }
@ -809,7 +875,7 @@ static void lcd_implementation_status_screen() {
int8_t pad = (LCD_WIDTH - utf8_strlen_P(pstr)) / 2; int8_t pad = (LCD_WIDTH - utf8_strlen_P(pstr)) / 2;
while (--pad >= 0) { lcd_put_wchar(' '); n--; } while (--pad >= 0) { lcd_put_wchar(' '); n--; }
} }
n -= lcd_put_u8str_max_rom(pstr, n); n -= lcd_put_u8str_max_P(pstr, n);
if (valstr) n -= lcd_put_u8str_max(valstr, n); if (valstr) n -= lcd_put_u8str_max(valstr, n);
for (; n > 0; --n) lcd_put_wchar(' '); for (; n > 0; --n) lcd_put_wchar(' ');
} }
@ -818,7 +884,7 @@ static void lcd_implementation_status_screen() {
uint8_t n = LCD_WIDTH - 2; uint8_t n = LCD_WIDTH - 2;
lcd_moveto(0, row); lcd_moveto(0, row);
lcd_put_wchar(sel ? pre_char : ' '); lcd_put_wchar(sel ? pre_char : ' ');
n -= lcd_put_u8str_max_rom(pstr, n); n -= lcd_put_u8str_max_P(pstr, n);
while (n--) lcd_put_wchar(' '); while (n--) lcd_put_wchar(' ');
lcd_put_wchar(post_char); lcd_put_wchar(post_char);
} }
@ -827,7 +893,7 @@ static void lcd_implementation_status_screen() {
uint8_t n = LCD_WIDTH - 2 - utf8_strlen(data); uint8_t n = LCD_WIDTH - 2 - utf8_strlen(data);
lcd_moveto(0, row); lcd_moveto(0, row);
lcd_put_wchar(sel ? pre_char : ' '); lcd_put_wchar(sel ? pre_char : ' ');
n -= lcd_put_u8str_max_rom(pstr, n); n -= lcd_put_u8str_max_P(pstr, n);
lcd_put_wchar(':'); lcd_put_wchar(':');
while (n--) lcd_put_wchar(' '); while (n--) lcd_put_wchar(' ');
lcd_put_u8str(data); lcd_put_u8str(data);
@ -836,10 +902,10 @@ static void lcd_implementation_status_screen() {
uint8_t n = LCD_WIDTH - 2 - utf8_strlen_P(data); uint8_t n = LCD_WIDTH - 2 - utf8_strlen_P(data);
lcd_moveto(0, row); lcd_moveto(0, row);
lcd_put_wchar(sel ? pre_char : ' '); lcd_put_wchar(sel ? pre_char : ' ');
n -= lcd_put_u8str_max_rom(pstr, n); n -= lcd_put_u8str_max_P(pstr, n);
lcd_put_wchar(':'); lcd_put_wchar(':');
while (n--) lcd_put_wchar(' '); while (n--) lcd_put_wchar(' ');
lcd_put_u8str_rom(data); lcd_put_u8str_P(data);
} }
#define DRAWMENU_SETTING_EDIT_GENERIC(_src) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', _src) #define DRAWMENU_SETTING_EDIT_GENERIC(_src) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', _src)
@ -847,7 +913,7 @@ static void lcd_implementation_status_screen() {
void lcd_implementation_drawedit(const char* pstr, const char* const value=NULL) { void lcd_implementation_drawedit(const char* pstr, const char* const value=NULL) {
lcd_moveto(1, 1); lcd_moveto(1, 1);
lcd_put_u8str_rom(pstr); lcd_put_u8str_P(pstr);
if (value != NULL) { if (value != NULL) {
lcd_put_wchar(':'); lcd_put_wchar(':');
int len = utf8_strlen(value); int len = utf8_strlen(value);
@ -1293,7 +1359,7 @@ static void lcd_implementation_status_screen() {
if (!isnan(ubl.z_values[x][inverted_y])) if (!isnan(ubl.z_values[x][inverted_y]))
lcd_put_u8str(ftostr43sign(ubl.z_values[x][inverted_y])); lcd_put_u8str(ftostr43sign(ubl.z_values[x][inverted_y]));
else else
lcd_put_u8str_rom(PSTR(" -----")); lcd_put_u8str_P(PSTR(" -----"));
#else // 16x4 or 20x4 display #else // 16x4 or 20x4 display
@ -1312,7 +1378,7 @@ static void lcd_implementation_status_screen() {
if (!isnan(ubl.z_values[x][inverted_y])) if (!isnan(ubl.z_values[x][inverted_y]))
lcd_put_u8str(ftostr43sign(ubl.z_values[x][inverted_y])); lcd_put_u8str(ftostr43sign(ubl.z_values[x][inverted_y]));
else else
lcd_put_u8str_rom(PSTR(" -----")); lcd_put_u8str_P(PSTR(" -----"));
#endif // LCD_HEIGHT > 3 #endif // LCD_HEIGHT > 3
} }

View file

@ -563,8 +563,7 @@ uint32_t USB_DMA_Status (uint32_t EPNum) {
uint32_t ptr, val; uint32_t ptr, val;
ptr = UDCA[EPAdr(EPNum)]; /* Current Descriptor */ ptr = UDCA[EPAdr(EPNum)]; /* Current Descriptor */
if (ptr == 0) if (ptr == 0) return (USB_DMA_INVALID);
return (USB_DMA_INVALID);
val = *((uint32_t *)(ptr + 3*4)); /* Status Information */ val = *((uint32_t *)(ptr + 3*4)); /* Status Information */
switch ((val >> 1) & 0x0F) { switch ((val >> 1) & 0x0F) {
@ -596,13 +595,8 @@ uint32_t USB_DMA_Status (uint32_t EPNum) {
uint32_t USB_DMA_BufAdr (uint32_t EPNum) { uint32_t USB_DMA_BufAdr (uint32_t EPNum) {
uint32_t ptr, val; uint32_t ptr, val;
ptr = UDCA[EPAdr(EPNum)]; /* Current Descriptor */ ptr = UDCA[EPAdr(EPNum)]; /* Current Descriptor */
if (ptr == 0) if (ptr == 0) return ((uint32_t)(-1)); /* DMA Invalid */
{
return ((uint32_t)(-1)); /* DMA Invalid */
}
val = *((uint32_t *)(ptr + 2*4)); /* Buffer Address */ val = *((uint32_t *)(ptr + 2*4)); /* Buffer Address */
return (val); /* Current Address */ return (val); /* Current Address */
} }
@ -619,12 +613,8 @@ uint32_t USB_DMA_BufAdr (uint32_t EPNum) {
uint32_t USB_DMA_BufCnt (uint32_t EPNum) { uint32_t USB_DMA_BufCnt (uint32_t EPNum) {
uint32_t ptr, val; uint32_t ptr, val;
ptr = UDCA[EPAdr(EPNum)]; /* Current Descriptor */ ptr = UDCA[EPAdr(EPNum)]; /* Current Descriptor */
if (ptr == 0) if (ptr == 0) return ((uint32_t)(-1)); /* DMA Invalid */
{
return ((uint32_t)(-1)); /* DMA Invalid */
}
val = *((uint32_t *)(ptr + 3*4)); /* Status Information */ val = *((uint32_t *)(ptr + 3*4)); /* Status Information */
return (val >> 16); /* Current Count */ return (val >> 16); /* Current Count */
} }