From 6f330f397e58130dcc9871fba33786575ac37f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20Jos=C3=A9=20Tagle?= Date: Sat, 26 May 2018 01:32:37 -0300 Subject: [PATCH] [2.0.x] Buffer overflow and scroll fix, UTF8 cleanup (#10844) --- Marlin/src/HAL/HAL_AVR/HAL_spi_AVR.cpp | 28 +-- Marlin/src/feature/bedlevel/ubl/ubl.h | 1 - Marlin/src/gcode/bedlevel/G26.cpp | 6 - Marlin/src/gcode/calibrate/G33.cpp | 7 +- Marlin/src/lcd/dogm/status_screen_DOGM.h | 91 ++++++--- .../src/lcd/dogm/status_screen_lite_ST7920.h | 75 +++++-- Marlin/src/lcd/fontutils.cpp | 184 ++---------------- Marlin/src/lcd/fontutils.h | 145 ++------------ Marlin/src/lcd/lcdprint.h | 14 +- Marlin/src/lcd/lcdprint_hd44780.cpp | 107 +++------- Marlin/src/lcd/lcdprint_u8g.cpp | 20 +- Marlin/src/lcd/u8g_fontutf8.cpp | 108 +++------- Marlin/src/lcd/u8g_fontutf8.h | 22 +-- Marlin/src/lcd/ultralcd.cpp | 68 ++++--- Marlin/src/lcd/ultralcd_impl_DOGM.h | 16 +- Marlin/src/lcd/ultralcd_impl_HD44780.h | 172 +++++++++++----- frameworks/CMSIS/LPC1768/lib/usb/usbhw.cpp | 20 +- 17 files changed, 413 insertions(+), 671 deletions(-) diff --git a/Marlin/src/HAL/HAL_AVR/HAL_spi_AVR.cpp b/Marlin/src/HAL/HAL_AVR/HAL_spi_AVR.cpp index 87323861a..4e4b24818 100644 --- a/Marlin/src/HAL/HAL_AVR/HAL_spi_AVR.cpp +++ b/Marlin/src/HAL/HAL_AVR/HAL_spi_AVR.cpp @@ -162,22 +162,15 @@ void spiBegin (void) { // away. When clock is not known, use a loop instead, which generates // shorter code. if (__builtin_constant_p(spiClock)) { - if (spiClock >= F_CPU / 2) { - clockDiv = 0; - } else if (spiClock >= F_CPU / 4) { - clockDiv = 1; - } else if (spiClock >= F_CPU / 8) { - clockDiv = 2; - } else if (spiClock >= F_CPU / 16) { - clockDiv = 3; - } else if (spiClock >= F_CPU / 32) { - clockDiv = 4; - } else if (spiClock >= F_CPU / 64) { - clockDiv = 5; - } else { - clockDiv = 6; - } - } else { + if (spiClock >= F_CPU / 2) clockDiv = 0; + else if (spiClock >= F_CPU / 4) clockDiv = 1; + else if (spiClock >= F_CPU / 8) clockDiv = 2; + else if (spiClock >= F_CPU / 16) clockDiv = 3; + else if (spiClock >= F_CPU / 32) clockDiv = 4; + else if (spiClock >= F_CPU / 64) clockDiv = 5; + else clockDiv = 6; + } + else { uint32_t clockSetting = F_CPU / 2; clockDiv = 0; while (clockDiv < 6 && spiClock < clockSetting) { @@ -187,8 +180,7 @@ void spiBegin (void) { } // Compensate for the duplicate fosc/64 - if (clockDiv == 6) - clockDiv = 7; + if (clockDiv == 6) clockDiv = 7; // Invert the SPI2X bit clockDiv ^= 0x1; diff --git a/Marlin/src/feature/bedlevel/ubl/ubl.h b/Marlin/src/feature/bedlevel/ubl/ubl.h index ae03b4d16..eb8823482 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl.h +++ b/Marlin/src/feature/bedlevel/ubl/ubl.h @@ -56,7 +56,6 @@ extern uint8_t ubl_cnt; /////////////////////////////////////////////////////////////////////////////////////////////////////// #if ENABLED(ULTRA_LCD) - extern char lcd_status_message[]; void lcd_quick_feedback(const bool clear_buttons); #endif diff --git a/Marlin/src/gcode/bedlevel/G26.cpp b/Marlin/src/gcode/bedlevel/G26.cpp index bcebf2d32..cbccdee89 100644 --- a/Marlin/src/gcode/bedlevel/G26.cpp +++ b/Marlin/src/gcode/bedlevel/G26.cpp @@ -135,10 +135,6 @@ // External references -#if ENABLED(ULTRA_LCD) - extern char lcd_status_message[]; -#endif - // Private functions 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(); - strcpy_P(lcd_status_message, PSTR("Done Priming")); // Hack to get the message up. May be obsolete. - lcd_setstatusPGM(PSTR("Done Priming"), 99); lcd_quick_feedback(true); lcd_external_control = false; diff --git a/Marlin/src/gcode/calibrate/G33.cpp b/Marlin/src/gcode/calibrate/G33.cpp index 15822262f..78b48790f 100644 --- a/Marlin/src/gcode/calibrate/G33.cpp +++ b/Marlin/src/gcode/calibrate/G33.cpp @@ -519,15 +519,12 @@ void GcodeSuite::G33() { } // Report settings - - const char *checkingac = PSTR("Checking... AC"); + const char* checkingac = PSTR("Checking... AC"); serialprintPGM(checkingac); if (verbose_level == 0) SERIAL_PROTOCOLPGM(" (DRY-RUN)"); if (set_up) SERIAL_PROTOCOLPGM(" (SET-UP)"); SERIAL_EOL(); - char mess[11]; - strcpy_P(mess, checkingac); - lcd_setstatus(mess); + lcd_setstatusPGM(checkingac); print_calibration_settings(_endstop_results, _angle_results); diff --git a/Marlin/src/lcd/dogm/status_screen_DOGM.h b/Marlin/src/lcd/dogm/status_screen_DOGM.h index 6d73803f1..f8842ba55 100644 --- a/Marlin/src/lcd/dogm/status_screen_DOGM.h +++ b/Marlin/src/lcd/dogm/status_screen_DOGM.h @@ -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); lcd_moveto(x - (str[0] != ' ' ? 0 : str[1] != ' ' ? 1 : 2) * DOG_CHAR_WIDTH / 2, y); lcd_put_u8str(str); - lcd_put_u8str_rom(PSTR(LCD_STR_DEGREE " ")); + lcd_put_u8str_P(PSTR(LCD_STR_DEGREE " ")); } #ifndef HEAT_INDICATOR_X @@ -113,7 +113,7 @@ FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const else { #if DISABLED(HOME_AFTER_DEACTIVATE) && DISABLED(DISABLE_REDUCED_ACCURACY_WARNING) if (!axis_known_position[axis]) - lcd_put_u8str_rom(axis == Z_AXIS ? PSTR(" ") : PSTR(" ")); + lcd_put_u8str_P(axis == Z_AXIS ? PSTR(" ") : PSTR(" ")); else #endif 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) { #if ENABLED(STATUS_MESSAGE_SCROLLING) static bool last_blink = false; - const uint8_t slen = utf8_strlen(lcd_status_message); - const char *stat = lcd_status_message + status_scroll_pos; - if (slen <= LCD_WIDTH) - lcd_put_u8str(stat); // The string isn't scrolling + + // Get the UTF8 character count of the string + uint8_t slen = utf8_strlen(lcd_status_message); + + // If the string fits into the LCD, just print it and do not scroll it + if (slen <= LCD_WIDTH) { + + // The string isn't scrolling and may not fill the screen + lcd_put_u8str(lcd_status_message); + + // Fill the rest with spaces + while (slen < LCD_WIDTH) { + lcd_put_wchar(' '); + ++slen; + } + } else { - if (status_scroll_pos <= slen - LCD_WIDTH) - lcd_put_u8str(stat); // The string fills the screen + // 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 { - uint8_t chars = LCD_WIDTH; - if (status_scroll_pos < slen) { // First string still visible - lcd_put_u8str(stat); // The string leaves space - chars -= slen - status_scroll_pos; // Amount of space left - } - lcd_put_wchar('.'); // Always at 1+ spaces left, draw a dot - if (--chars) { - if (status_scroll_pos < slen + 1) // Draw a second dot if there's space - --chars, lcd_put_wchar('.'); - if (chars) lcd_put_u8str_max(lcd_status_message, chars); // Print a second copy of the message + // 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 + if (--chars) { // Draw a second dot if there's space + lcd_put_wchar('.'); + if (--chars) { + // Print a second copy of the message + lcd_put_u8str_max(lcd_status_message, LCD_PIXEL_WIDTH - ((rlen+2) * DOG_CHAR_WIDTH)); + } } } if (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++; - if (++status_scroll_pos >= slen + 2) status_scroll_pos = 0; + + // Adjust by complete UTF8 characters + 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 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 } @@ -417,7 +458,7 @@ static void lcd_implementation_status_screen() { lcd_put_wchar('%'); lcd_setFont(FONT_MENU); 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_put_wchar(LCD_STR_FILAM_MUL[0]); #endif @@ -437,10 +478,10 @@ static void lcd_implementation_status_screen() { lcd_implementation_status_message(blink); } else { - lcd_put_u8str_rom(PSTR(LCD_STR_FILAM_DIA)); + lcd_put_u8str_P(PSTR(LCD_STR_FILAM_DIA)); lcd_put_wchar(':'); 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_u8str(mstring); lcd_put_wchar('%'); diff --git a/Marlin/src/lcd/dogm/status_screen_lite_ST7920.h b/Marlin/src/lcd/dogm/status_screen_lite_ST7920.h index 78d879472..4102cb9ed 100644 --- a/Marlin/src/lcd/dogm/status_screen_lite_ST7920.h +++ b/Marlin/src/lcd/dogm/status_screen_lite_ST7920.h @@ -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) { set_ddram_address(DDRAM_LINE_4); begin_data(); + const uint8_t lcd_len = 16; #if ENABLED(STATUS_MESSAGE_SCROLLING) - const uint8_t lcd_len = 16; - const uint8_t padding = 2; - uint8_t str_len = strlen(str); - // Trim whitespace at the end of the str, as for some reason - // messages like "Card Inserted" are padded with many spaces - while (str_len && str[str_len - 1] == ' ') str_len--; + uint8_t slen = utf8_strlen(str); - if (str_len <= lcd_len) { - // It all fits on the LCD without scrolling + // If the string fits into the LCD, just print it and do not scroll it + if (slen <= lcd_len) { + + // The string isn't scrolling and may not fill the screen write_str(str); + + // Fill the rest with spaces + while (slen < lcd_len) { + write_byte(' '); + ++slen; + } } else { - // Print the message repeatedly until covering the LCD - uint8_t c = status_scroll_pos; - for (uint8_t n = 0; n < lcd_len; n++) { - write_byte(c < str_len ? str[c] : ' '); - c++; - c %= str_len + padding; // Wrap around + // String is larger than the available space in screen. + + // Get a pointer to the next valid UTF8 character + const char *stat = str + 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_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 - if (status_scroll_pos == str_len + padding) - status_scroll_pos = 0; + // Adjust by complete UTF8 characters + if (status_scroll_offset < slen) { + status_scroll_offset++; + while (!START_OF_UTF8_CHAR(str[status_scroll_offset])) + status_scroll_offset++; + } else - status_scroll_pos++; + status_scroll_offset = 0; } #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 } @@ -792,7 +827,7 @@ void ST7920_Lite_Status_Screen::update_status_or_position(bool forceUpdate) { */ if (forceUpdate || status_changed()) { #if ENABLED(STATUS_MESSAGE_SCROLLING) - status_scroll_pos = 0; + status_scroll_offset = 0; #endif #if STATUS_EXPIRE_SECONDS countdown = lcd_status_message[0] ? STATUS_EXPIRE_SECONDS : 0; diff --git a/Marlin/src/lcd/fontutils.cpp b/Marlin/src/lcd/fontutils.cpp index 39f47bde3..08afb2ed8 100644 --- a/Marlin/src/lcd/fontutils.cpp +++ b/Marlin/src/lcd/fontutils.cpp @@ -16,56 +16,14 @@ #include "fontutils.h" -uint8_t read_byte_ram(uint8_t * str) { return *str; } -uint8_t read_byte_rom(uint8_t * str) { return pgm_read_byte(str); } +uint8_t read_byte_ram(uint8_t * str) { + return *str; +} -#if DEBUG - #ifdef ARDUINO - #include - #include +uint8_t read_byte_rom(uint8_t * str) { + return pgm_read_byte(str); +} - 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 * @@ -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 retcomp; - FU_ASSERT(NULL != ret_idx); - /* 查找合适的位置 */ if (num_data < 1) { *ret_idx = 0; - DBGMSG (PFDBG_CATLOG_PF, PFDBG_LEVEL_ERROR, "num_data(%" PRIuSZ ") < 1", num_data); return -1; } - /* 折半查找 */ - /* 为了不出现负数,以免缩小索引的所表示的数据范围 - * (负数表明减少一位二进制位的使用), - * 内部 ileft 和 iright使用从1开始的下标, - * 即1表示C语言中的0, 2表示语言中的1,以此类推。 - * 对外还是使用以 0 为开始的下标 - */ size_t i = 0, ileft = 1, iright = num_data; bool flg_found = false; 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; else if (ileft >= i + 2) *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; } -/** - * @brief 转换 UTF-8 编码的一个字符为本地的 Unicode 字符(wchar_t) - * - * @param pstart : 存储 UTF-8 字符的指针 - * @param cb_read_byte : 读取字符的函数;用于8位MCU ROM - * @param pval : 需要返回的 Unicode 字符存放地址指针 - * - * @return 成功返回下个 UTF-8 字符的位置 - * - * 转换 UTF-8 编码的一个字符为本地的 Unicode 字符(wchar_t) - */ +/* This function gets the character at the pstart position, interpreting UTF8 multybyte sequences + and returns the pointer to the next character */ uint8_t* get_utf8_value_cb(uint8_t *pstart, read_byte_cb_t cb_read_byte, wchar_t *pval) { uint32_t val = 0; uint8_t *p = pstart; - FU_ASSERT(NULL != pstart); - FU_ASSERT(NULL != cb_read_byte); - uint8_t valcur = cb_read_byte(p); if (0 == (0x80 & 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); p++; } - else if (0x80 == (0xC0 & valcur)) { - /* error? */ - TRACE("ERR 1"); + else if (0x80 == (0xC0 & valcur)) for (; 0x80 == (0xC0 & valcur); ) { p++; valcur = cb_read_byte(p); } - } - else { - /* error */ - TRACE("ERR 2"); + else 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; return p; } -// uint8_t * get_utf8_value_cb (uint8_t *pstart, read_byte_cb_t cb_read_byte, wchar_t *pval); -int utf8_strlen_cb(const char *pstart, read_byte_cb_t cb_read_byte) { - wchar_t ch; - uint8_t *pnext; - int cnt = 0; +static inline uint8_t utf8_strlen_cb(const char *pstart, read_byte_cb_t cb_read_byte) { - 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); - if (pnext == NULL || ch == 0) break; + if (!ch) break; cnt++; - TRACE("cnt=%d, ch=0x%X", cnt, (int)ch); } return cnt; } -int -my_strlen_P(const char *pstart) -{ - 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(const char *pstart) { return utf8_strlen_cb(pstart, read_byte_ram); } -uint8_t utf8_strlen_P(const char *pstart) { 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; +uint8_t utf8_strlen_P(const char *pstart) { + return utf8_strlen_cb(pstart, read_byte_rom); } -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); -} diff --git a/Marlin/src/lcd/fontutils.h b/Marlin/src/lcd/fontutils.h index d44537a8e..98dc7ea3b 100644 --- a/Marlin/src/lcd/fontutils.h +++ b/Marlin/src/lcd/fontutils.h @@ -9,151 +9,40 @@ #ifndef _FONT_UTILS_H #define _FONT_UTILS_H -#define DEBUG 0 - -#ifdef ARDUINO - #include -#else // ARDUINO - #include - #include - #include -#endif // ARDUINO - -#ifndef pgm_read_word_near // __AVR__ - #include - #include - #include - //#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 -#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 +#include "../core/macros.h" #include // wchar_t #include // 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 - // sizeof(wchar_t)=2; sizeof(size_t)=2; sizeof(uint32_t)=4; - // sizeof(int)=2; sizeof(long)=4; sizeof(unsigned)=2; - //#undef wchar_t - #define wchar_t uint32_t - //typedef uint32_t wchar_t; +uint8_t read_byte_ram(uint8_t * str); +uint8_t read_byte_rom(uint8_t * str); -#else - - #include // ssize_t - #include - // x86_64 - // sizeof(wchar_t)=4; sizeof(size_t)=8; sizeof(uint32_t)=4; - // 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 +// 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; +// sizeof(int)=2; sizeof(long)=4; sizeof(unsigned)=2; +//#undef wchar_t +#define wchar_t uint32_t +//typedef uint32_t wchar_t; #ifndef NUM_ARRAY #define NUM_ARRAY(a) (sizeof(a)/sizeof((a)[0])) #endif // NUM_ARRAY - -#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; +typedef uint16_t pixel_len_t; #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"*/ 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); -//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); +/* Get the character, decoding multibyte UTF8 characters and returning a pointer to the start of the next UTF8 character */ +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_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 -#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 diff --git a/Marlin/src/lcd/lcdprint.h b/Marlin/src/lcd/lcdprint.h index 009611071..c26640165 100644 --- a/Marlin/src/lcd/lcdprint.h +++ b/Marlin/src/lcd/lcdprint.h @@ -17,11 +17,7 @@ #include "u8g_fontutf8.h" #endif -#define PRINTABLE(C) (((C) & 0xC0u) != 0x80u) - -#ifdef __cplusplus - extern "C" { -#endif +#define START_OF_UTF8_CHAR(C) (((C) & 0xC0u) != 0x80u) 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 */ -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); -#ifdef __cplusplus - } -#endif - -#define lcd_put_u8str_rom(str) lcd_put_u8str_max_rom(str, PIXEL_LEN_NOLIMIT) +inline int lcd_put_u8str_P(const char *str) { return lcd_put_u8str_max_P(str, PIXEL_LEN_NOLIMIT); } inline int lcd_put_u8str(const char* str) { return lcd_put_u8str_max(str, PIXEL_LEN_NOLIMIT); } diff --git a/Marlin/src/lcd/lcdprint_hd44780.cpp b/Marlin/src/lcd/lcdprint_hd44780.cpp index c7e58e164..8d81ac01f 100644 --- a/Marlin/src/lcd/lcdprint_hd44780.cpp +++ b/Marlin/src/lcd/lcdprint_hd44780.cpp @@ -24,20 +24,13 @@ #include "fontutils.h" #include "lcdprint.h" -#if defined(ARDUINO) - #include "ultralcd_common_HD44780.h" - #ifndef LCD_CLASS - #include - #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)); +#include "ultralcd_common_HD44780.h" +#ifndef LCD_CLASS + #include + #define LCD_CLASS LiquidCrystal #endif +extern LCD_CLASS lcd; +LCD_CLASS *plcd = &lcd; int lcd_glyph_height(void) { return 1; } @@ -878,25 +871,10 @@ static const hd44780_charmap_t g_hd44780_charmap_common[] PROGMEM = { /* return v1 - v2 */ static int hd44780_charmap_compare(hd44780_charmap_t * v1, hd44780_charmap_t * v2) { - FU_ASSERT(NULL != v1); - 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"); + if (v1->uchar < v2->uchar) return -1; - } else if (v1->uchar > v2->uchar) { - TRACE("compare return 1"); + else if (v1->uchar > v2->uchar) 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; } @@ -909,9 +887,7 @@ static int pf_bsearch_cb_comp_hd4map_pgm(void *userdata, size_t idx, void * data #if DEBUG -int -test_hd44780_charmap(hd44780_charmap_t *data, size_t size, char *name, char flg_show_contents) -{ +int test_hd44780_charmap(hd44780_charmap_t *data, size_t size, char *name, char flg_show_contents) { int ret; size_t idx = 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; } -int -test_hd44780_charmap_all(void) -{ +int test_hd44780_charmap_all(void) { int flg_error = 0; if (test_hd44780_charmap(g_hd44780_charmap_device, NUM_ARRAY(g_hd44780_charmap_device), "g_hd44780_charmap_device", 0) < 0) { flg_error = 1; @@ -986,18 +960,17 @@ test_hd44780_charmap_all(void) #endif // DEBUG void lcd_moveto(int col, int row) { - TRACE("Move to: (%d,%d)", col, row); - _lcd_setcursor(col, row); + plcd->setCursor(col, row); } // return < 0 on error // return the advanced cols int lcd_put_wchar_max(wchar_t c, pixel_len_t max_length) { + // find the HD44780 internal ROM first int ret; size_t idx = 0; hd44780_charmap_t pinval; - hd44780_charmap_t localval; hd44780_charmap_t *copy_address = NULL; pinval.uchar = c; 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 if (c < 128) { - //TRACE("draw char: regular %d", (int)c); - _lcd_write((uint8_t)c); + plcd->write((uint8_t)c); return 1; } 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); if (ret >= 0) { copy_address = (hd44780_charmap_t *)(g_hd44780_charmap_device + idx); - } else { + } + 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) copy_address = (hd44780_charmap_t *)(g_hd44780_charmap_common + idx); } if (ret >= 0) { + hd44780_charmap_t localval; // found - FU_ASSERT(NULL != copy_address); memcpy_P(&localval, copy_address, sizeof(localval)); - FU_ASSERT((localval.uchar == c) && (localval.uchar == pinval.uchar)); - TRACE("draw char: %" PRIu32 "(0x%" PRIX32 ") at ROM %d(+%d)", c, c, (int)localval.idx, (int)localval.idx2); - _lcd_write(localval.idx); + plcd->write(localval.idx); if (max_length >= 2 && localval.idx2 > 0) { - _lcd_write(localval.idx2); + plcd->write(localval.idx2); return 2; } return 1; } - // print '?' instead - TRACE("draw char: Not found " PRIu32 "(0x%" PRIX32 ")", c, c); - _lcd_write((uint8_t)'?'); + + // Not found, print '?' instead + plcd->write((uint8_t)'?'); 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 * * @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 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 */ -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) { - wchar_t ch; - uint8_t *p, *pend; +static int lcd_put_u8str_max_cb(const char * utf8_str, uint8_t (*cb_read_byte)(uint8_t * str), pixel_len_t max_length) { pixel_len_t ret = 0; - - TRACE("BEGIN lcd_put_u8str_max_cb(len=%d, maxlen=%d)", len, max_length); - pend = (uint8_t *)utf8_str + len; - for (p = (uint8_t *)utf8_str; (p < pend) && (ret < max_length); ) { - ch = 0; + uint8_t *p = (uint8_t *)utf8_str; + while (ret < max_length) { + wchar_t ch = 0; p = get_utf8_value_cb(p, cb_read_byte, &ch); - if (NULL == p) { - TRACE("No more char, break ..."); - break; - } - FU_ASSERT(ret < max_length); + if (!p) break; ret += lcd_put_wchar_max(ch, max_length - ret); } return (int)ret; } 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); - 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); + return lcd_put_u8str_max_cb(utf8_str, read_byte_ram, max_length); } -int lcd_put_u8str_max_rom(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); - 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); +int lcd_put_u8str_max_P(const char * utf8_str_P, pixel_len_t max_length) { + return lcd_put_u8str_max_cb(utf8_str_P, read_byte_rom, max_length); } #endif // DOGLCD diff --git a/Marlin/src/lcd/lcdprint_u8g.cpp b/Marlin/src/lcd/lcdprint_u8g.cpp index 37ddd4f08..39ac8acc3 100644 --- a/Marlin/src/lcd/lcdprint_u8g.cpp +++ b/Marlin/src/lcd/lcdprint_u8g.cpp @@ -25,25 +25,22 @@ extern U8GLIB *pu8g; int lcd_glyph_height(void) { return u8g_GetFontBBXHeight(pu8g->getU8g()); - //return u8g_GetFontBBXOffY(pu8g->getU8g()); } void lcd_moveto(int col, int row) { - TRACE("Move to: (%d,%d)", 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) { if (c < 256) { - TRACE("draw char: regular %d", (int)c); _lcd_write((char)c); return u8g_GetFontBBXWidth(pu8g->getU8g()); } unsigned int x = pu8g->getPrintCol(), y = pu8g->getPrintRow(), 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); 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(), y = pu8g->getPrintRow(), 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); 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(), y = pu8g->getPrintRow(), 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); return ret; } -#else // !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 +#endif // DOGLCD diff --git a/Marlin/src/lcd/u8g_fontutf8.cpp b/Marlin/src/lcd/u8g_fontutf8.cpp index a90403528..b79d9906e 100644 --- a/Marlin/src/lcd/u8g_fontutf8.cpp +++ b/Marlin/src/lcd/u8g_fontutf8.cpp @@ -18,28 +18,6 @@ //////////////////////////////////////////////////////////// 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 * @@ -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); -//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 */ static int fontinfo_compare(uxg_fontinfo_t * v1, uxg_fontinfo_t * v2) { - FU_ASSERT(NULL != v1); - FU_ASSERT(NULL != v2); - if (v1->page < v2->page) - return -1; - 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) - return -1; - else if (v1->begin > v2->end) - return 1; + if (v1->end < v2->begin) return -1; + else if (v1->begin > v2->end) return 1; 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) { uxg_fontinfo_t *fntinfo = (uxg_fontinfo_t*)userdata; 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); } @@ -92,7 +59,6 @@ typedef struct _font_group_t { static int fontgroup_init(font_group_t * root, const uxg_fontinfo_t * fntinfo, int number) { root->m_fntifo = fntinfo; root->m_fntinfo_num = number; - 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) return NULL; - memcpy_from_rom(&vcmp, root->m_fntifo + idx, sizeof(vcmp)); + memcpy_P(&vcmp, root->m_fntifo + idx, sizeof(vcmp)); 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) { uint8_t buf[2] = {0, 0}; - const font_t * fntpqm = NULL; - - TRACE("fontgroup_drawwchar char=%d(0x%X)", (int)val, (int)val); - fntpqm = (font_t*)fontgroup_find(group, val); - if (NULL == fntpqm) { + const font_t * fntpqm = (font_t*)fontgroup_find(group, val); + if (!fntpqm) { + // Unknown char, use default font buf[0] = (uint8_t)(val & 0xFF); fntpqm = fnt_default; - TRACE("Unknown char %d(0x%X), use default font", (int)val, (int)val); } if (fnt_default != fntpqm) { 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 } - //TRACE("set font: %p; (default=%p)", fntpqm, UXG_DEFAULT_FONT); + 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 */ -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) { - uint8_t *pend = (uint8_t*)utf8_msg + len_msg; - for (uint8_t *p = (uint8_t*)utf8_msg; p < pend; ) { +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 *p = (uint8_t*)utf8_msg; + for (;;) { wchar_t val = 0; p = get_utf8_value_cb(p, cb_read_byte, &val); - if (NULL == p) { - TRACE("No more char, break ..."); - break; - } + if (!val) break; fontgroup_drawwchar(group, fnt_default, val, userdata, cb_draw_ram); } } //////////////////////////////////////////////////////////// -static char flag_fontgroup_inited1 = 0; -#define flag_fontgroup_inited flag_fontgroup_inited1 +static bool flag_fontgroup_was_inited = false; static font_group_t g_fontgroup_root = {NULL, 0}; /** * @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) { - flag_fontgroup_inited = 1; + flag_fontgroup_was_inited = 1; return fontgroup_init(&g_fontgroup_root, fntinfo, number); } @@ -179,22 +138,17 @@ struct _uxg_drawu8_data_t { 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; - FU_ASSERT(NULL != userdata); if (pdata->fnt_prev != fnt_current) { u8g_SetFont(pdata->pu8g, (const u8g_fntpgm_uint8_t*)fnt_current); //u8g_SetFontPosBottom(pdata->pu8g); pdata->fnt_prev = fnt_current; } - 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); + if ((pdata->max_width != PIXEL_LEN_NOLIMIT) && (pdata->adv + u8g_GetStrPixelWidth(pdata->pu8g, (char*)msg) > pdata->max_width)) return 1; - } - TRACE("Draw string 0x%X", (int)msg[0]); pdata->adv += u8g_DrawStr(pdata->pu8g, pdata->x + pdata->adv, pdata->y, (char*) msg); - //TRACE("adv pos= %d", pdata->adv); return 0; } @@ -260,7 +214,7 @@ unsigned int uxg_DrawUtf8Str(u8g_t *pu8g, unsigned int x, unsigned int y, const data.adv = 0; data.max_width = max_width; 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); 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); if (!uxg_Utf8FontIsInited()) { - TRACE("Error, utf8string not inited!"); u8g_DrawStrP(pu8g, x, y, (const u8g_pgm_uint8_t *)PSTR("Err: utf8 font not initialized.")); return 0; } @@ -295,19 +248,15 @@ unsigned int uxg_DrawUtf8StrP(u8g_t *pu8g, unsigned int x, unsigned int y, const data.adv = 0; data.max_width = max_width; data.fnt_prev = NULL; - TRACE("call fontgroup_drawstring"); - fontgroup_drawstring(group, fnt_default, utf8_msg, my_strlen_P(utf8_msg), read_byte_rom, (void*)&data, fontgroup_cb_draw_u8g); - TRACE("restore font"); + fontgroup_drawstring(group, fnt_default, utf8_msg, read_byte_rom, (void*)&data, fontgroup_cb_draw_u8g); u8g_SetFont(pu8g, (const u8g_fntpgm_uint8_t*)fnt_default); - TRACE("return %d", data.adv); return data.adv; } 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; - FU_ASSERT(NULL != userdata); if (pdata->fnt_prev != fnt_current) { u8g_SetFont(pdata->pu8g, (const u8g_fntpgm_uint8_t*)fnt_current); 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; const font_t *fnt_default = uxg_GetFont(pu8g); - if (!uxg_Utf8FontIsInited()) { - TRACE("Err: utf8 font not initialized."); - return -1; - } + if (!uxg_Utf8FontIsInited()) return -1; memset(&data, 0, sizeof(data)); data.pu8g = pu8g; 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); return data.adv; @@ -361,14 +307,12 @@ int uxg_GetUtf8StrPixelWidthP(u8g_t *pu8g, const char *utf8_msg) { font_group_t *group = &g_fontgroup_root; const font_t *fnt_default = uxg_GetFont(pu8g); - if (!uxg_Utf8FontIsInited()) { - TRACE("Err: utf8 font not initialized."); - return -1; - } + if (!uxg_Utf8FontIsInited()) return -1; + memset(&data, 0, sizeof(data)); data.pu8g = pu8g; 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); return data.adv; } diff --git a/Marlin/src/lcd/u8g_fontutf8.h b/Marlin/src/lcd/u8g_fontutf8.h index 9d3c46c6a..8f637e173 100644 --- a/Marlin/src/lcd/u8g_fontutf8.h +++ b/Marlin/src/lcd/u8g_fontutf8.h @@ -12,11 +12,6 @@ #include #include "fontutils.h" -#ifdef __cplusplus -extern "C" { -#endif - - // the macro to indicate a UTF-8 string // 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 @@ -30,21 +25,16 @@ typedef struct _uxg_fontinfo_t { const u8g_fntpgm_uint8_t *fntdata; } uxg_fontinfo_t; -extern int uxg_SetUtf8Fonts (const uxg_fontinfo_t * fntinfo, int number); // fntinfo is type of PROGMEM -extern char uxg_Utf8FontIsInited(void); +int uxg_SetUtf8Fonts (const uxg_fontinfo_t * fntinfo, int number); // fntinfo is type of PROGMEM -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); -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_DrawUtf8Str (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); -extern int uxg_GetUtf8StrPixelWidthP(u8g_t *pu8g, const char *utf8_msg); +int uxg_GetUtf8StrPixelWidth(u8g_t *pu8g, const char *utf8_msg); +int uxg_GetUtf8StrPixelWidthP(u8g_t *pu8g, const char *utf8_msg); #define uxg_GetFont(puxg) ((puxg)->font) -#ifdef __cplusplus -} -#endif - #endif // _UXG_FONTUTF8_H diff --git a/Marlin/src/lcd/ultralcd.cpp b/Marlin/src/lcd/ultralcd.cpp index 9b77c8051..8bf8dd77c 100644 --- a/Marlin/src/lcd/ultralcd.cpp +++ b/Marlin/src/lcd/ultralcd.cpp @@ -80,7 +80,7 @@ #else #define MAX_MESSAGE_LENGTH CHARSIZE * 2 * (LCD_WIDTH) #endif - uint8_t status_scroll_pos = 0; + uint8_t status_scroll_offset = 0; #else #define MAX_MESSAGE_LENGTH CHARSIZE * (LCD_WIDTH) #endif @@ -5360,30 +5360,8 @@ void lcd_update() { } // 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) { - pad_message_string(); - #if !(ENABLED(LCD_PROGRESS_BAR) && (PROGRESS_MSG_EXPIRE > 0)) UNUSED(persist); #endif @@ -5401,7 +5379,7 @@ void lcd_finishstatus(const bool persist=false) { #endif #if ENABLED(STATUS_MESSAGE_SCROLLING) - status_scroll_pos = 0; + status_scroll_offset = 0; #endif } @@ -5413,7 +5391,26 @@ bool lcd_hasstatus() { return (lcd_status_message[0] != '\0'); } void lcd_setstatus(const char * const message, const bool persist) { 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); } @@ -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 < lcd_status_message_level) return; 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); } diff --git a/Marlin/src/lcd/ultralcd_impl_DOGM.h b/Marlin/src/lcd/ultralcd_impl_DOGM.h index 06d8342e9..f9b0fb452 100644 --- a/Marlin/src/lcd/ultralcd_impl_DOGM.h +++ b/Marlin/src/lcd/ultralcd_impl_DOGM.h @@ -341,9 +341,9 @@ void lcd_kill_screen() { lcd_moveto(0, h4 * 1); lcd_put_u8str(lcd_status_message); 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_put_u8str_rom(PSTR(MSG_PLEASE_RESET)); + lcd_put_u8str_P(PSTR(MSG_PLEASE_RESET)); } 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; 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) { 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)) { uint8_t n = LCD_WIDTH - (START_COL) - 2; 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(' '); } lcd_moveto(LCD_PIXEL_WIDTH - (DOG_CHAR_WIDTH), row_y2); 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)); uint8_t n = LCD_WIDTH - (START_COL) - 2 - vallen; n *= DOG_CHAR_WIDTH; - n -= lcd_put_u8str_max_rom(pstr, n); + n -= lcd_put_u8str_max_P(pstr, 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); - 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); if (onpage) { lcd_moveto(0, baseline); - lcd_put_u8str_rom(pstr); + lcd_put_u8str_P(pstr); } 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])) lcd_put_u8str(ftostr43sign(ubl.z_values[x_plot][y_plot])); else - lcd_put_u8str_rom(PSTR(" -----")); + lcd_put_u8str_P(PSTR(" -----")); } } diff --git a/Marlin/src/lcd/ultralcd_impl_HD44780.h b/Marlin/src/lcd/ultralcd_impl_HD44780.h index 7511d97c6..66b69aab8 100644 --- a/Marlin/src/lcd/ultralcd_impl_HD44780.h +++ b/Marlin/src/lcd/ultralcd_impl_HD44780.h @@ -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 - void lcd_scroll(const int16_t col, const int16_t line, const char* const text, const int16_t len, const int16_t time) { - #if 1 - lcd_put_u8str(text); - #else - 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_put_u8str(tmp); - delay(time / MAX(n, 1)); + void lcd_scroll(const uint8_t col, const uint8_t line, const char* const text, const uint8_t len, const int16_t time) { + uint8_t slen = utf8_strlen_P(text); + if (slen < len) { + // Fits into, + lcd_moveto(col, line); + lcd_put_u8str_max_P(text, len); + while (slen < len) { + lcd_put_wchar(' '); + ++slen; } - #endif + 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++; + } + } } static void logo_lines(const char* const extra) { 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, 1); lcd_put_u8str_rom(PSTR("|Marlin|")); lcd_put_u8str_rom(extra); - lcd_moveto(indent, 2); lcd_put_wchar('\x02'); lcd_put_u8str_rom(PSTR( "------" )); lcd_put_wchar('\x03'); + lcd_moveto(indent, 0); lcd_put_wchar('\x00'); lcd_put_u8str_P(PSTR( "------" )); lcd_put_wchar('\x01'); + 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_P(PSTR( "------" )); lcd_put_wchar('\x03'); } void lcd_bootscreen() { @@ -379,7 +404,7 @@ void lcd_implementation_clear() { lcd.clear(); } lcd_erase_line(3); \ if (utf8_strlen(STRING) <= LCD_WIDTH) { \ 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); \ } \ else { \ @@ -452,10 +477,10 @@ void lcd_kill_screen() { lcd_moveto(0, 2); #else lcd_moveto(0, 2); - lcd_put_u8str_rom(PSTR(MSG_HALTED)); + lcd_put_u8str_P(PSTR(MSG_HALTED)); lcd_moveto(0, 3); #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 { #if DISABLED(HOME_AFTER_DEACTIVATE) && DISABLED(DISABLE_REDUCED_ACCURACY_WARNING) if (!axis_known_position[axis]) - lcd_put_u8str_rom(axis == Z_AXIS ? PSTR(" ") : PSTR(" ")); + lcd_put_u8str_P(axis == Z_AXIS ? PSTR(" ") : PSTR(" ")); else #endif lcd_put_u8str(value); @@ -634,11 +659,11 @@ static void lcd_implementation_status_screen() { #if ENABLED(SDSUPPORT) lcd_moveto(0, 2); - lcd_put_u8str_rom(PSTR("SD")); + lcd_put_u8str_P(PSTR("SD")); if (IS_SD_PRINTING) lcd_put_u8str(itostr3(card.percentDone())); else - lcd_put_u8str_rom(PSTR("---")); + lcd_put_u8str_P(PSTR("---")); lcd_put_wchar('%'); #endif // SDSUPPORT @@ -698,11 +723,11 @@ static void lcd_implementation_status_screen() { #if LCD_WIDTH >= 20 && ENABLED(SDSUPPORT) lcd_moveto(7, 2); - lcd_put_u8str_rom(PSTR("SD")); + lcd_put_u8str_P(PSTR("SD")); if (IS_SD_PRINTING) lcd_put_u8str(itostr3(card.percentDone())); else - lcd_put_u8str_rom(PSTR("---")); + lcd_put_u8str_P(PSTR("---")); lcd_put_wchar('%'); #endif // LCD_WIDTH >= 20 && SDSUPPORT @@ -739,9 +764,9 @@ static void lcd_implementation_status_screen() { // Show Filament Diameter and Volumetric Multiplier % // After allowing lcd_status_message to show for 5 seconds 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_rom(PSTR(" V")); + lcd_put_u8str_P(PSTR(" V")); lcd_put_u8str(itostr3(100.0 * ( parser.volumetric_enabled ? 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) static bool last_blink = false; - const uint8_t slen = utf8_strlen(lcd_status_message); - const char *stat = lcd_status_message + status_scroll_pos; - if (slen <= LCD_WIDTH) - lcd_put_u8str(stat); // The string isn't scrolling + + // Get the UTF8 character count of the string + uint8_t slen = utf8_strlen(lcd_status_message); + + // If the string fits into the LCD, just print it and do not scroll it + if (slen <= LCD_WIDTH) { + + // The string isn't scrolling and may not fill the screen + lcd_put_u8str(lcd_status_message); + + // Fill the rest with spaces + while (slen < LCD_WIDTH) { + lcd_put_wchar(' '); + ++slen; + } + } else { - if (status_scroll_pos <= slen - LCD_WIDTH) - lcd_put_u8str(stat); // The string fills the screen + // 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 { - uint8_t chars = LCD_WIDTH; - if (status_scroll_pos < slen) { // First string still visible - lcd_put_u8str(stat); // The string leaves space - chars -= slen - status_scroll_pos; // Amount of space left - } - lcd_put_wchar('.'); // Always at 1+ spaces left, draw a dot - if (--chars) { - if (status_scroll_pos < slen + 1) // Draw a second dot if there's space - --chars, lcd_put_wchar('.'); - if (chars) lcd_put_u8str_max(lcd_status_message, chars); // Print a second copy of the message + + // 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 + if (--chars) { // Draw a second dot if there's space + lcd_put_wchar('.'); + if (--chars) + lcd_put_u8str_max(lcd_status_message, chars); // Print a second copy of the message } } if (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++; - if (++status_scroll_pos >= slen + 2) status_scroll_pos = 0; + + // Adjust by complete UTF8 characters + 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 - 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 } @@ -809,7 +875,7 @@ static void lcd_implementation_status_screen() { int8_t pad = (LCD_WIDTH - utf8_strlen_P(pstr)) / 2; 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); for (; n > 0; --n) lcd_put_wchar(' '); } @@ -818,7 +884,7 @@ static void lcd_implementation_status_screen() { uint8_t n = LCD_WIDTH - 2; lcd_moveto(0, row); 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(' '); lcd_put_wchar(post_char); } @@ -827,7 +893,7 @@ static void lcd_implementation_status_screen() { uint8_t n = LCD_WIDTH - 2 - utf8_strlen(data); lcd_moveto(0, row); 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(':'); while (n--) lcd_put_wchar(' '); lcd_put_u8str(data); @@ -836,10 +902,10 @@ static void lcd_implementation_status_screen() { uint8_t n = LCD_WIDTH - 2 - utf8_strlen_P(data); lcd_moveto(0, row); 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(':'); 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) @@ -847,7 +913,7 @@ static void lcd_implementation_status_screen() { void lcd_implementation_drawedit(const char* pstr, const char* const value=NULL) { lcd_moveto(1, 1); - lcd_put_u8str_rom(pstr); + lcd_put_u8str_P(pstr); if (value != NULL) { lcd_put_wchar(':'); int len = utf8_strlen(value); @@ -1293,7 +1359,7 @@ static void lcd_implementation_status_screen() { if (!isnan(ubl.z_values[x][inverted_y])) lcd_put_u8str(ftostr43sign(ubl.z_values[x][inverted_y])); else - lcd_put_u8str_rom(PSTR(" -----")); + lcd_put_u8str_P(PSTR(" -----")); #else // 16x4 or 20x4 display @@ -1312,7 +1378,7 @@ static void lcd_implementation_status_screen() { if (!isnan(ubl.z_values[x][inverted_y])) lcd_put_u8str(ftostr43sign(ubl.z_values[x][inverted_y])); else - lcd_put_u8str_rom(PSTR(" -----")); + lcd_put_u8str_P(PSTR(" -----")); #endif // LCD_HEIGHT > 3 } diff --git a/frameworks/CMSIS/LPC1768/lib/usb/usbhw.cpp b/frameworks/CMSIS/LPC1768/lib/usb/usbhw.cpp index 8fa8f829e..379baca15 100644 --- a/frameworks/CMSIS/LPC1768/lib/usb/usbhw.cpp +++ b/frameworks/CMSIS/LPC1768/lib/usb/usbhw.cpp @@ -563,8 +563,7 @@ uint32_t USB_DMA_Status (uint32_t EPNum) { uint32_t ptr, val; ptr = UDCA[EPAdr(EPNum)]; /* Current Descriptor */ - if (ptr == 0) - return (USB_DMA_INVALID); + if (ptr == 0) return (USB_DMA_INVALID); val = *((uint32_t *)(ptr + 3*4)); /* Status Information */ 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 ptr, val; - ptr = UDCA[EPAdr(EPNum)]; /* Current Descriptor */ - if (ptr == 0) - { - return ((uint32_t)(-1)); /* DMA Invalid */ - } - + if (ptr == 0) return ((uint32_t)(-1)); /* DMA Invalid */ val = *((uint32_t *)(ptr + 2*4)); /* Buffer 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 ptr, val; - ptr = UDCA[EPAdr(EPNum)]; /* Current Descriptor */ - if (ptr == 0) - { - return ((uint32_t)(-1)); /* DMA Invalid */ - } + if (ptr == 0) return ((uint32_t)(-1)); /* DMA Invalid */ val = *((uint32_t *)(ptr + 3*4)); /* Status Information */ return (val >> 16); /* Current Count */ } @@ -695,7 +685,7 @@ void USB_IRQHandler (void) { #if USB_SOF_EVENT /* Start of Frame Interrupt */ if (disr & FRAME_INT) { - LPC_USB->USBDevIntClr = FRAME_INT; + LPC_USB->USBDevIntClr = FRAME_INT; USB_SOF_Event(); } #endif @@ -703,7 +693,7 @@ void USB_IRQHandler (void) { #if USB_ERROR_EVENT /* Error Interrupt */ if (disr & ERR_INT) { - LPC_USB->USBDevIntClr = ERR_INT; + LPC_USB->USBDevIntClr = ERR_INT; WrCmd(CMD_RD_ERR_STAT); val = RdCmdDat(DAT_RD_ERR_STAT); USB_Error_Event(val);