[2.0.x] Buffer overflow and scroll fix, UTF8 cleanup (#10844)
This commit is contained in:
parent
235facd545
commit
6f330f397e
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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('%');
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 <Arduino.h>
|
||||
#include <stdarg.h>
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -9,151 +9,40 @@
|
|||
#ifndef _FONT_UTILS_H
|
||||
#define _FONT_UTILS_H
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
#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 <Arduino.h>
|
||||
#include "../core/macros.h"
|
||||
#include <stddef.h> // wchar_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
|
||||
// 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 <sys/types.h> // ssize_t
|
||||
#include <assert.h>
|
||||
// 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 <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
|
||||
|
|
|
@ -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); }
|
||||
|
||||
|
|
|
@ -24,20 +24,13 @@
|
|||
#include "fontutils.h"
|
||||
#include "lcdprint.h"
|
||||
|
||||
#if defined(ARDUINO)
|
||||
#include "ultralcd_common_HD44780.h"
|
||||
#ifndef LCD_CLASS
|
||||
#include <LiquidCrystal.h>
|
||||
#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 <LiquidCrystal.h>
|
||||
#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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -12,11 +12,6 @@
|
|||
#include <U8glib.h>
|
||||
#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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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(" -----"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue