🚸 Progress display followup (#24879)

This commit is contained in:
EvilGremlin 2022-12-08 01:08:53 +03:00 committed by Scott Lahteine
parent c86f20010d
commit 0efeedf262
7 changed files with 122 additions and 147 deletions

View File

@ -1476,24 +1476,26 @@
#endif // HAS_DISPLAY || DWIN_LCD_PROUI #endif // HAS_DISPLAY || DWIN_LCD_PROUI
// Add the G-code 'M73' to set / report the current job progress // Add 'M73' to set print job progress, overrides Marlin's built-in estimate
//#define SET_PROGRESS_MANUALLY //#define SET_PROGRESS_MANUALLY
#if ENABLED(SET_PROGRESS_MANUALLY) #if ENABLED(SET_PROGRESS_MANUALLY)
//#define SET_PROGRESS_PERCENT // Add 'P' parameter to set percentage done, otherwise use Marlin's estimate #define SET_PROGRESS_PERCENT // Add 'P' parameter to set percentage done
//#define SET_REMAINING_TIME // Add 'R' parameter to set remaining time, otherwise use Marlin's estimate #define SET_REMAINING_TIME // Add 'R' parameter to set remaining time
//#define SET_INTERACTION_TIME // Add 'C' parameter to set time until next filament change or other user interaction //#define SET_INTERACTION_TIME // Add 'C' parameter to set time until next filament change or other user interaction
#if ENABLED(SET_INTERACTION_TIME) //#define M73_REPORT // Report M73 values to host
#define SHOW_INTERACTION_TIME // Display time until next user interaction ('C' = filament change) #if BOTH(M73_REPORT, SDSUPPORT)
#define M73_REPORT_SD_ONLY // Report only when printing from SD
#endif #endif
//#define M73_REPORT // Report progress to host with 'M73'
#endif #endif
// LCD Print Progress options, multiple can be rotated depending on screen layout // LCD Print Progress options. Multiple times may be displayed in turn.
#if HAS_DISPLAY && EITHER(SDSUPPORT, SET_PROGRESS_MANUALLY) #if HAS_DISPLAY && EITHER(SDSUPPORT, SET_PROGRESS_MANUALLY)
#define SHOW_PROGRESS_PERCENT // Show print progress percentage (doesn't affect progress bar) #define SHOW_PROGRESS_PERCENT // Show print progress percentage (doesn't affect progress bar)
#define SHOW_ELAPSED_TIME // Display elapsed printing time (prefix 'E') #define SHOW_ELAPSED_TIME // Display elapsed printing time (prefix 'E')
//#define SHOW_REMAINING_TIME // Display estimated time to completion (prefix 'R') //#define SHOW_REMAINING_TIME // Display estimated time to completion (prefix 'R')
#if ENABLED(SET_INTERACTION_TIME)
#define SHOW_INTERACTION_TIME // Display time until next user interaction ('C' = filament change)
#endif
//#define PRINT_PROGRESS_SHOW_DECIMALS // Show/report progress with decimal digits, not all UIs support this //#define PRINT_PROGRESS_SHOW_DECIMALS // Show/report progress with decimal digits, not all UIs support this
#if EITHER(HAS_MARLINUI_HD44780, IS_TFTGLCD_PANEL) #if EITHER(HAS_MARLINUI_HD44780, IS_TFTGLCD_PANEL)

View File

@ -33,10 +33,6 @@
#include "../../lcd/e3v2/proui/dwin.h" #include "../../lcd/e3v2/proui/dwin.h"
#endif #endif
#if ENABLED(M73_REPORT)
#define M73_REPORT_PRUSA
#endif
/** /**
* M73: Set percentage complete (for display on LCD) * M73: Set percentage complete (for display on LCD)
* *
@ -46,10 +42,9 @@
* M73 C12 ; Set next interaction countdown to 12 minutes * M73 C12 ; Set next interaction countdown to 12 minutes
* M73 ; Report current values * M73 ; Report current values
* *
* Use a shorter-than-Průša report format: * M73 Progress: ---%; Time left: -----m; Change: -----m;
* M73 Percent done: ---%; Time left: -----m; Change: -----m;
* *
* When PRINT_PROGRESS_SHOW_DECIMALS is enabled - reports percent with 100 / 23.4 / 3.45 format * When PRINT_PROGRESS_SHOW_DECIMALS is enabled - reports percent with 100% / 23.4% / 3.45% format
* *
*/ */
void GcodeSuite::M73() { void GcodeSuite::M73() {
@ -79,18 +74,19 @@ void GcodeSuite::M73() {
#endif #endif
#if ENABLED(M73_REPORT) #if ENABLED(M73_REPORT)
{ if (TERN1(M73_REPORT_SD_ONLY, IS_SD_PRINTING())) {
SERIAL_ECHO_MSG( SERIAL_ECHO_START();
TERN(M73_REPORT_PRUSA, "M73 Percent done: ", "Progress: ") SERIAL_ECHOPGM(" M73");
, TERN(PRINT_PROGRESS_SHOW_DECIMALS, permyriadtostr4(ui.get_progress_permyriad()), ui.get_progress_percent()) #if ENABLED(SET_PROGRESS_PERCENT)
SERIAL_ECHOPGM(" Progress: ", TERN(PRINT_PROGRESS_SHOW_DECIMALS, permyriadtostr4(ui.get_progress_permyriad()), ui.get_progress_percent()), "%;");
#endif
#if ENABLED(SET_REMAINING_TIME) #if ENABLED(SET_REMAINING_TIME)
, TERN(M73_REPORT_PRUSA, "; Print time remaining in mins: ", "%; Time left: "), ui.remaining_time / 60 SERIAL_ECHOPGM(" Time left: ", ui.remaining_time / 60, "m;");
#endif #endif
#if ENABLED(SET_INTERACTION_TIME) #if ENABLED(SET_INTERACTION_TIME)
, TERN(M73_REPORT_PRUSA, "; Change in mins: ", "m; Change: "), ui.interaction_time / 60 SERIAL_ECHOPGM(" Change: ", ui.interaction_time / 60, "m;");
#endif #endif
, TERN(M73_REPORT_PRUSA, ";", "m") SERIAL_EOL();
);
} }
#endif #endif
} }

View File

@ -760,7 +760,7 @@ void MarlinUI::draw_status_message(const bool blink) {
#if HAS_PRINT_PROGRESS #if HAS_PRINT_PROGRESS
#define TPOFFSET (LCD_WIDTH - 1) #define TPOFFSET (LCD_WIDTH - 1)
static uint8_t timepos = TPOFFSET - 6; static uint8_t timepos = TPOFFSET - 6;
static char buffer[14]; static char buffer[8];
static lcd_uint_t pc, pr; static lcd_uint_t pc, pr;
#if ENABLED(SHOW_PROGRESS_PERCENT) #if ENABLED(SHOW_PROGRESS_PERCENT)
@ -776,9 +776,10 @@ void MarlinUI::draw_status_message(const bool blink) {
#endif #endif
#if ENABLED(SHOW_REMAINING_TIME) #if ENABLED(SHOW_REMAINING_TIME)
void MarlinUI::drawRemain() { void MarlinUI::drawRemain() {
const duration_t remaint = ui.get_remaining_time();
if (printJobOngoing()) { if (printJobOngoing()) {
const duration_t remaint = ui.get_remaining_time();
timepos = TPOFFSET - remaint.toDigital(buffer); timepos = TPOFFSET - remaint.toDigital(buffer);
TERN_(NOT(LCD_INFO_SCREEN_STYLE), lcd_put_lchar(timepos - 1, 2, 0x20);)
lcd_put_lchar(TERN(LCD_INFO_SCREEN_STYLE, 11, timepos), 2, 'R'); lcd_put_lchar(TERN(LCD_INFO_SCREEN_STYLE, 11, timepos), 2, 'R');
lcd_put_u8str(buffer); lcd_put_u8str(buffer);
} }
@ -789,6 +790,7 @@ void MarlinUI::draw_status_message(const bool blink) {
const duration_t interactt = ui.interaction_time; const duration_t interactt = ui.interaction_time;
if (printingIsActive() && interactt.value) { if (printingIsActive() && interactt.value) {
timepos = TPOFFSET - interactt.toDigital(buffer); timepos = TPOFFSET - interactt.toDigital(buffer);
TERN_(NOT(LCD_INFO_SCREEN_STYLE), lcd_put_lchar(timepos - 1, 2, 0x20);)
lcd_put_lchar(TERN(LCD_INFO_SCREEN_STYLE, 11, timepos), 2, 'C'); lcd_put_lchar(TERN(LCD_INFO_SCREEN_STYLE, 11, timepos), 2, 'C');
lcd_put_u8str(buffer); lcd_put_u8str(buffer);
} }
@ -796,11 +798,11 @@ void MarlinUI::draw_status_message(const bool blink) {
#endif #endif
#if ENABLED(SHOW_ELAPSED_TIME) #if ENABLED(SHOW_ELAPSED_TIME)
void MarlinUI::drawElapsed() { void MarlinUI::drawElapsed() {
const duration_t elapsedt = print_job_timer.duration();
if (printJobOngoing()) { if (printJobOngoing()) {
const duration_t elapsedt = print_job_timer.duration();
timepos = TPOFFSET - elapsedt.toDigital(buffer); timepos = TPOFFSET - elapsedt.toDigital(buffer);
TERN_(NOT(LCD_INFO_SCREEN_STYLE), lcd_put_lchar(timepos - 1, 2, 0x20);)
lcd_put_lchar(TERN(LCD_INFO_SCREEN_STYLE, 11, timepos), 2, 'E'); lcd_put_lchar(TERN(LCD_INFO_SCREEN_STYLE, 11, timepos), 2, 'E');
//lcd_put_lchar(timepos, 2, LCD_STR_CLOCK[0]);
lcd_put_u8str(buffer); lcd_put_u8str(buffer);
} }
} }
@ -919,7 +921,7 @@ void MarlinUI::draw_status_screen() {
#if LCD_WIDTH < 20 #if LCD_WIDTH < 20
#if HAS_PRINT_PROGRESS #if HAS_PRINT_PROGRESS
pc = 0, pr = 2; pc = 0; pr = 2;
rotate_progress(); rotate_progress();
#endif #endif
@ -1006,14 +1008,14 @@ void MarlinUI::draw_status_screen() {
#if LCD_WIDTH >= 20 #if LCD_WIDTH >= 20
#if HAS_PRINT_PROGRESS #if HAS_PRINT_PROGRESS
pc = timepos - 7, pr = 2; pc = 6; pr = 2;
rotate_progress(); rotate_progress();
#else #else
char c; char c;
uint16_t per; uint16_t per;
#if HAS_FAN0 #if HAS_FAN0
if (true if (true
#if EXTRUDERS && ENABLED(ADAPTIVE_FAN_SLOWING) #if BOTH(HAS_EXTRUDERS, ADAPTIVE_FAN_SLOWING)
&& (blink || thermalManager.fan_speed_scaler[0] < 128) && (blink || thermalManager.fan_speed_scaler[0] < 128)
#endif #endif
) { ) {
@ -1087,7 +1089,7 @@ void MarlinUI::draw_status_screen() {
_draw_bed_status(blink); _draw_bed_status(blink);
#elif HAS_PRINT_PROGRESS #elif HAS_PRINT_PROGRESS
#define DREW_PRINT_PROGRESS 1 #define DREW_PRINT_PROGRESS 1
pc = 0, pr = 2; pc = 0; pr = 2;
rotate_progress(); rotate_progress();
#endif #endif
@ -1095,7 +1097,7 @@ void MarlinUI::draw_status_screen() {
// All progress strings // All progress strings
// //
#if HAS_PRINT_PROGRESS && !DREW_PRINT_PROGRESS #if HAS_PRINT_PROGRESS && !DREW_PRINT_PROGRESS
pc = LCD_WIDTH - 9, pr = 2; pc = LCD_WIDTH - 9; pr = 2;
rotate_progress(); rotate_progress();
#endif #endif
#endif // LCD_INFO_SCREEN_STYLE 1 #endif // LCD_INFO_SCREEN_STYLE 1

View File

@ -596,23 +596,58 @@ FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const
#endif // HAS_CUTTER #endif // HAS_CUTTER
#if HAS_PRINT_PROGRESS
FORCE_INLINE void _draw_print_progress() { #if HAS_PRINT_PROGRESS // UNTESTED!!!
if (!PanelDetected) return; #define TPOFFSET (LCD_WIDTH - 1)
const uint8_t progress = ui._get_progress(); static uint8_t timepos = TPOFFSET - 6;
#if ENABLED(SDSUPPORT)
lcd_put_u8str(F("SD")); #if ENABLED(SHOW_PROGRESS_PERCENT)
#elif ENABLED(SET_PROGRESS_PERCENT) void MarlinUI::drawPercent() {
lcd_put_u8str(F("P:")); const uint8_t progress = ui.get_progress_percent();
#endif if (progress) {
if (progress) lcd_moveto(0, 2);
lcd.print(ui8tostr3rj(progress)); lcd_put_u8str(F(TERN(IS_SD_PRINTING, "SD", "P:")));
else lcd.print(TERN(PRINT_PROGRESS_SHOW_DECIMALS, permyriadtostr4(ui.get_progress_permyriad()), ui8tostr3rj(progress)));
lcd_put_u8str(F("---"));
lcd.write('%'); lcd.write('%');
} }
}
#endif
#if ENABLED(SHOW_REMAINING_TIME)
void MarlinUI::drawRemain() {
if (printJobOngoing()) {
const duration_t remaint = ui.get_remaining_time();
char buffer[10];
timepos = TPOFFSET - remaint.toDigital(buffer);
lcd_moveto(timepos, 1);
lcd.write('R');
lcd.print(buffer);
}
}
#endif
#if ENABLED(SHOW_INTERACTION_TIME)
void MarlinUI::drawInter() {
const duration_t interactt = ui.interaction_time;
if (printingIsActive() && interactt.value) {
char buffer[10];
timepos = TPOFFSET - interactt.toDigital(buffer);
lcd_moveto(timepos, 1);
lcd.write('C');
lcd.print(buffer);
}
}
#endif
#if ENABLED(SHOW_ELAPSED_TIME)
void MarlinUI::drawElapsed() {
if (printJobOngoing()) {
const duration_t elapsedt = print_job_timer.duration();
char buffer[10];
timepos = TPOFFSET - elapsedt.toDigital(buffer);
lcd_moveto(timepos, 1);
lcd.write('E');
lcd.print(buffer);
}
}
#endif
#endif // HAS_PRINT_PROGRESS #endif // HAS_PRINT_PROGRESS
#if ENABLED(LCD_PROGRESS_BAR) #if ENABLED(LCD_PROGRESS_BAR)
@ -796,23 +831,12 @@ void MarlinUI::draw_status_screen() {
#endif #endif
// //
// Line 2 - feedrate, , time // Line 2 - feedrate, progress %, progress time
// //
lcd_moveto(0, 1); lcd_moveto(0, 1);
lcd_put_u8str(F("FR")); lcd.print(i16tostr3rj(feedrate_percentage)); lcd.write('%'); lcd_put_u8str(F("FR")); lcd.print(i16tostr3rj(feedrate_percentage)); lcd.write('%');
ui.rotate_progress(); // UNTESTED!!!
#if BOTH(SDSUPPORT, HAS_PRINT_PROGRESS)
lcd_moveto(LCD_WIDTH / 2 - 3, 1);
_draw_print_progress();
#endif
char buffer[10];
duration_t elapsed = print_job_timer.duration();
uint8_t len = elapsed.toDigital(buffer);
lcd_moveto((LCD_WIDTH - 1) - len, 1);
lcd.write(LCD_STR_CLOCK[0]); lcd.print(buffer);
// //
// Line 3 - progressbar // Line 3 - progressbar

View File

@ -445,50 +445,44 @@ FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const
// Prepare strings for progress display // Prepare strings for progress display
#if HAS_PRINT_PROGRESS #if HAS_PRINT_PROGRESS
#define _PRGR_INFO_X(len) (LCD_PIXEL_WIDTH - (len) * (MENU_FONT_WIDTH)) static MarlinUI::progress_t progress = 0;
#define PCENTERED 1 // center percent value over progress bar, else align to the right static char bufferc[13];
static uint8_t lastProgress = 0xFF;
static u8g_uint_t progress_bar_solid_width = 0; static void prepare_time_string(const duration_t &time, char prefix) {
char str[9];
memset(&bufferc[2], 0x20, 5); // partialy fill with spaces to avoid artifacts and terminator
bufferc[0] = prefix;
bufferc[1] = ':';
int str_length = time.toDigital(str, time.value >= 60*60*24L);
strcpy(&bufferc[sizeof(bufferc) - str_length - 1], str);
}
#if ENABLED(SHOW_PROGRESS_PERCENT) #if ENABLED(SHOW_PROGRESS_PERCENT)
static char progress_string[5];
static u8g_uint_t progress_x_pos;
void MarlinUI::drawPercent() { void MarlinUI::drawPercent() {
if (progress_string[0]) { if (progress != 0) {
lcd_put_u8str(progress_x_pos, EXTRAS_BASELINE, progress_string); #define PCENTERED 1 // center percent value over progress bar, else align to the right
lcd_put_u8str(F("%")); #define PPOS TERN(PCENTERED, 4, 0)
#define PLEN TERN(PRINT_PROGRESS_SHOW_DECIMALS, 4, 3)
memset(&bufferc, 0x20, 12);
memcpy(&bufferc[PPOS], TERN(PRINT_PROGRESS_SHOW_DECIMALS, permyriadtostr4(progress), ui8tostr3rj(progress / (PROGRESS_SCALE))), PLEN);
bufferc[PPOS+PLEN] = '%';
} }
} }
#endif #endif
#if ENABLED(SHOW_REMAINING_TIME) #if ENABLED(SHOW_REMAINING_TIME)
static char remaining_string[10];
static u8g_uint_t remaining_x_pos = 0;
void MarlinUI::drawRemain() { void MarlinUI::drawRemain() {
if (printJobOngoing()){ if (printJobOngoing() && get_remaining_time() != 0)
lcd_put_u8str(PROGRESS_BAR_X, EXTRAS_BASELINE, F("R:")); prepare_time_string(get_remaining_time(), 'R'); }
lcd_put_u8str(remaining_x_pos, EXTRAS_BASELINE, remaining_string);
}
}
#endif #endif
#if ENABLED(SHOW_INTERACTION_TIME) #if ENABLED(SHOW_INTERACTION_TIME)
static char interaction_string[10];
static u8g_uint_t interaction_x_pos = 0;
void MarlinUI::drawInter() { void MarlinUI::drawInter() {
if (printingIsActive() && interaction_string[0]) { if (printingIsActive() && interaction_time)
lcd_put_u8str(PROGRESS_BAR_X, EXTRAS_BASELINE, F("C:")); prepare_time_string(interaction_time, 'C'); }
lcd_put_u8str(interaction_x_pos, EXTRAS_BASELINE, interaction_string);
}
}
#endif #endif
#if ENABLED(SHOW_ELAPSED_TIME) #if ENABLED(SHOW_ELAPSED_TIME)
static char elapsed_string[10];
static u8g_uint_t elapsed_x_pos = 0;
static uint8_t lastElapsed;
void MarlinUI::drawElapsed() { void MarlinUI::drawElapsed() {
if (printJobOngoing()) { if (printJobOngoing())
lcd_put_u8str(PROGRESS_BAR_X, EXTRAS_BASELINE, F("E:")); prepare_time_string(print_job_timer.duration(), 'E'); }
lcd_put_u8str(elapsed_x_pos, EXTRAS_BASELINE, elapsed_string);
}
}
#endif #endif
#endif // HAS_PRINT_PROGRESS #endif // HAS_PRINT_PROGRESS
@ -514,6 +508,8 @@ void MarlinUI::draw_status_screen() {
const bool show_e_total = TERN0(LCD_SHOW_E_TOTAL, printingIsActive()); const bool show_e_total = TERN0(LCD_SHOW_E_TOTAL, printingIsActive());
static u8g_uint_t progress_bar_solid_width = 0;
// At the first page, generate new display values // At the first page, generate new display values
if (first_page) { if (first_page) {
#if ANIM_HBCC #if ANIM_HBCC
@ -551,59 +547,16 @@ void MarlinUI::draw_status_screen() {
strcpy(mstring, i16tostr3rj(planner.volumetric_percent(parser.volumetric_enabled))); strcpy(mstring, i16tostr3rj(planner.volumetric_percent(parser.volumetric_enabled)));
#endif #endif
// Progress / elapsed / estimation updates and string formatting to avoid float math on each LCD draw // Progress update to avoid float math on each LCD draw
#if HAS_PRINT_PROGRESS #if HAS_PRINT_PROGRESS
const progress_t progress = TERN(HAS_PRINT_PROGRESS_PERMYRIAD, get_progress_permyriad, get_progress_percent)(); progress = TERN(HAS_PRINT_PROGRESS_PERMYRIAD, get_progress_permyriad, get_progress_percent)();
duration_t elapsedt = print_job_timer.duration();
const uint8_t p = progress & 0xFF, ev = elapsedt.value & 0xFF; static uint8_t lastProgress = 0xFF;
const uint8_t p = progress & 0xFF;
if (p != lastProgress) { if (p != lastProgress) {
lastProgress = p; lastProgress = p;
progress_bar_solid_width = u8g_uint_t((PROGRESS_BAR_WIDTH - 2) * (progress / (PROGRESS_SCALE)) * 0.01f); progress_bar_solid_width = u8g_uint_t((PROGRESS_BAR_WIDTH - 2) * (progress / (PROGRESS_SCALE)) * 0.01f);
#if ENABLED(SHOW_PROGRESS_PERCENT)
if (progress == 0)
progress_string[0] = '\0';
else
strcpy(progress_string, TERN(PRINT_PROGRESS_SHOW_DECIMALS, permyriadtostr4(progress), ui8tostr3rj(progress / (PROGRESS_SCALE))));
progress_x_pos = TERN(PCENTERED, 77, _PRGR_INFO_X(strlen(progress_string) + 1));
#endif
} }
#if ENABLED(SHOW_INTERACTION_TIME)
if (!(interaction_time)) {
interaction_string[0] = '\0';
interaction_x_pos = _PRGR_INFO_X(0);
}
else {
const duration_t interactt = ui.interaction_time;
interactt.toDigital(interaction_string, interactt.value >= 60*60*24L);
interaction_x_pos = _PRGR_INFO_X(strlen(interaction_string));
}
#endif
#if ENABLED(SHOW_ELAPSED_TIME)
if (ev != lastElapsed) {
lastElapsed = ev;
const uint8_t len = elapsedt.toDigital(elapsed_string, elapsedt.value >= 60*60*24L);
elapsed_x_pos = _PRGR_INFO_X(len);
}
#endif
#if ENABLED(SHOW_REMAINING_TIME)
if (!(ev & 0x3)) {
uint32_t timeval = get_remaining_time();
if (!timeval) {
remaining_string[0] = '\0';
remaining_x_pos = _PRGR_INFO_X(0);
}
else {
const duration_t remaint = timeval;
const uint8_t len = remaint.toDigital(remaining_string, remaint.value >= 60*60*24L);
remaining_x_pos = _PRGR_INFO_X(len);
}
}
#endif
#endif #endif
} }
@ -796,8 +749,10 @@ void MarlinUI::draw_status_screen() {
u8g.drawBox(PROGRESS_BAR_X + 1, PROGRESS_BAR_Y + 1, progress_bar_solid_width, 2); u8g.drawBox(PROGRESS_BAR_X + 1, PROGRESS_BAR_Y + 1, progress_bar_solid_width, 2);
// Progress strings // Progress strings
if (PAGE_CONTAINS(EXTRAS_BASELINE - INFO_FONT_ASCENT, EXTRAS_BASELINE - 1)) if (PAGE_CONTAINS(EXTRAS_BASELINE - INFO_FONT_ASCENT, EXTRAS_BASELINE - 1)){
ui.rotate_progress(); ui.rotate_progress();
lcd_put_u8str(PROGRESS_BAR_X, EXTRAS_BASELINE, bufferc);
}
#endif #endif
// //

View File

@ -366,6 +366,8 @@ void MarlinUI::draw_status_screen() {
); );
} }
// TODO!
// //
// Elapsed time // Elapsed time
// //

View File

@ -84,12 +84,6 @@ const char* i8tostr3rj(const int8_t x) {
conv[6] = DIGIMOD(xx, 10); conv[6] = DIGIMOD(xx, 10);
return &conv[3]; return &conv[3];
} }
else if (xx % 100 == 0) {
conv[4] = ' ';
conv[5] = RJDIGIT(xx, 1000);
conv[6] = DIGIMOD(xx, 100);
return &conv[4];
}
else { else {
conv[3] = DIGIMOD(xx, 100); conv[3] = DIGIMOD(xx, 100);
conv[4] = '.'; conv[4] = '.';