Added a new feature to the "M115" code:

"M115 Umajor.minor.revision-flavor" will trigger a dialog
on the display if the "upgrade" firmware version number is higher
than the current version number.
This commit is contained in:
bubnikv 2016-07-07 20:26:59 +02:00
parent d7c75f2060
commit 0b372bfc94
10 changed files with 374 additions and 9 deletions

View File

@ -61,6 +61,7 @@
#include "language.h"
#include "pins_arduino.h"
#include "math.h"
#include "util.h"
#ifdef BLINKM
#include "BlinkM.h"
@ -1227,6 +1228,7 @@ static inline bool code_seen(const char *code) { return (strchr_pointer = str
static inline float code_value() { return strtod(strchr_pointer+1, NULL); }
static inline long code_value_long() { return strtol(strchr_pointer+1, NULL, 10); }
static inline int16_t code_value_short() { return int16_t(strtol(strchr_pointer+1, NULL, 10)); };
static inline uint8_t code_value_uint8() { return uint8_t(strtol(strchr_pointer+1, NULL, 10)); };
#define DEFINE_PGM_READ_ANY(type, reader) \
static inline type pgm_read_any(const type *p) \
@ -2766,7 +2768,7 @@ void process_commands()
}
break;
case 44: // M45: Reset the bed skew and offset calibration.
case 44: // M44: Prusa3D: Reset the bed skew and offset calibration.
// Reset the skew and offset in both RAM and EEPROM.
reset_bed_offset_and_skew();
// Reset world2machine_rotation_and_skew and world2machine_shift, therefore
@ -2775,7 +2777,7 @@ void process_commands()
world2machine_revert_to_uncorrected();
break;
case 45: // M46: bed skew and offset with manual Z up
case 45: // M45: Prusa3D: bed skew and offset with manual Z up
{
// Disable the default update procedure of the display. We will do a modal dialog.
lcd_update_enable(false);
@ -2835,7 +2837,12 @@ void process_commands()
break;
}
#if 1
case 47:
// M47: Prusa3D: Show end stops dialog on the display.
lcd_diag_show_end_stops();
break;
#if 0
case 48: // M48: scan the bed induction sensor points, print the sensor trigger coordinates to the serial line for visualization on the PC.
{
// Disable the default update procedure of the display. We will do a modal dialog.
@ -2874,10 +2881,6 @@ void process_commands()
}
#endif
case 47:
lcd_diag_show_end_stops();
break;
// M48 Z-Probe repeatability measurement function.
//
// Usage: M48 <n #_samples> <X X_position_for_samples> <Y Y_position_for_samples> <V Verbose_Level> <L legs_of_movement_prior_to_doing_probe>
@ -3488,7 +3491,16 @@ Sigma_Exit:
}
break;
case 115: // M115
SERIAL_PROTOCOLRPGM(MSG_M115_REPORT);
if (code_seen('V')) {
// Report the Prusa version number.
SERIAL_PROTOCOLLNRPGM(FW_VERSION_STR_P());
} else if (code_seen('U')) {
// Check the firmware version provided. If the firmware version provided by the U code is higher than the currently running firmware,
// pause the print and ask the user to upgrade the firmware.
show_upgrade_dialog_if_version_newer(++ strchr_pointer);
} else {
SERIAL_PROTOCOLRPGM(MSG_M115_REPORT);
}
break;
case 117: // M117 display message
starpos = (strchr(strchr_pointer + 5,'*'));

View File

@ -1760,6 +1760,32 @@ const char * const MSG_MOVE_Z_LANG_TABLE[LANG_NUM] PROGMEM = {
MSG_MOVE_Z_PL
};
const char MSG_NEW_FIRMWARE_AVAILABLE_EN[] PROGMEM = "New firmware version available:";
const char MSG_NEW_FIRMWARE_AVAILABLE_CZ[] PROGMEM = "Vysla nova verze firmware:";
const char MSG_NEW_FIRMWARE_AVAILABLE_IT[] PROGMEM = "New firmware version available:";
const char MSG_NEW_FIRMWARE_AVAILABLE_ES[] PROGMEM = "New firmware version available:";
const char MSG_NEW_FIRMWARE_AVAILABLE_PL[] PROGMEM = "New firmware version available:";
const char * const MSG_NEW_FIRMWARE_AVAILABLE_LANG_TABLE[LANG_NUM] PROGMEM = {
MSG_NEW_FIRMWARE_AVAILABLE_EN,
MSG_NEW_FIRMWARE_AVAILABLE_CZ,
MSG_NEW_FIRMWARE_AVAILABLE_IT,
MSG_NEW_FIRMWARE_AVAILABLE_ES,
MSG_NEW_FIRMWARE_AVAILABLE_PL
};
const char MSG_NEW_FIRMWARE_PLEASE_UPGRADE_EN[] PROGMEM = "Please upgrade.";
const char MSG_NEW_FIRMWARE_PLEASE_UPGRADE_CZ[] PROGMEM = "Prosim aktualizujte.";
const char MSG_NEW_FIRMWARE_PLEASE_UPGRADE_IT[] PROGMEM = "Please upgrade.";
const char MSG_NEW_FIRMWARE_PLEASE_UPGRADE_ES[] PROGMEM = "Please upgrade.";
const char MSG_NEW_FIRMWARE_PLEASE_UPGRADE_PL[] PROGMEM = "Please upgrade.";
const char * const MSG_NEW_FIRMWARE_PLEASE_UPGRADE_LANG_TABLE[LANG_NUM] PROGMEM = {
MSG_NEW_FIRMWARE_PLEASE_UPGRADE_EN,
MSG_NEW_FIRMWARE_PLEASE_UPGRADE_CZ,
MSG_NEW_FIRMWARE_PLEASE_UPGRADE_IT,
MSG_NEW_FIRMWARE_PLEASE_UPGRADE_ES,
MSG_NEW_FIRMWARE_PLEASE_UPGRADE_PL
};
const char MSG_NO_EN[] PROGMEM = "No";
const char MSG_NO_CZ[] PROGMEM = "Ne";
const char MSG_NO_IT[] PROGMEM = "No";

View File

@ -280,6 +280,10 @@ extern const char* const MSG_MOVE_Y_LANG_TABLE[LANG_NUM];
#define MSG_MOVE_Y LANG_TABLE_SELECT(MSG_MOVE_Y_LANG_TABLE)
extern const char* const MSG_MOVE_Z_LANG_TABLE[LANG_NUM];
#define MSG_MOVE_Z LANG_TABLE_SELECT(MSG_MOVE_Z_LANG_TABLE)
extern const char* const MSG_NEW_FIRMWARE_AVAILABLE_LANG_TABLE[LANG_NUM];
#define MSG_NEW_FIRMWARE_AVAILABLE LANG_TABLE_SELECT(MSG_NEW_FIRMWARE_AVAILABLE_LANG_TABLE)
extern const char* const MSG_NEW_FIRMWARE_PLEASE_UPGRADE_LANG_TABLE[LANG_NUM];
#define MSG_NEW_FIRMWARE_PLEASE_UPGRADE LANG_TABLE_SELECT(MSG_NEW_FIRMWARE_PLEASE_UPGRADE_LANG_TABLE)
extern const char* const MSG_NO_LANG_TABLE[LANG_NUM];
#define MSG_NO LANG_TABLE_SELECT(MSG_NO_LANG_TABLE)
extern const char* const MSG_NOT_COLOR_LANG_TABLE[LANG_NUM];

View File

@ -308,4 +308,7 @@
#define MSG_BED_LEVELING_FAILED_POINT_LOW "Kalibrace Z selhala. Sensor nesepnul. Znecistena tryska? Cekam na reset."
#define MSG_BED_LEVELING_FAILED_POINT_HIGH "Kalibrace Z selhala. Sensor sepnul prilis vysoko. Cekam na reset."
#define MSG_NEW_FIRMWARE_AVAILABLE "Vysla nova verze firmware:"
#define MSG_NEW_FIRMWARE_PLEASE_UPGRADE "Prosim aktualizujte."
#endif // LANGUAGE_EN_H

View File

@ -301,4 +301,7 @@
#define MSG_BED_LEVELING_FAILED_POINT_LOW "Bed leveling failed. Sensor didnt trigger. Debris on nozzle? Waiting for reset."
#define MSG_BED_LEVELING_FAILED_POINT_HIGH "Bed leveling failed. Sensor triggered too high. Waiting for reset."
#define MSG_NEW_FIRMWARE_AVAILABLE "New firmware version available:"
#define MSG_NEW_FIRMWARE_PLEASE_UPGRADE "Please upgrade."
#endif // LANGUAGE_EN_H

View File

@ -8,6 +8,8 @@
#include "stepper.h"
#include "ConfigurationStore.h"
#include <string.h>
#include "util.h"
//#include "Configuration.h"
@ -659,7 +661,14 @@ static void lcd_support_menu()
MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
MENU_ITEM(back, PSTR(MSG_FW_VERSION " - " FW_version), lcd_main_menu);
// Ideally this block would be optimized out by the compiler.
const uint8_t fw_string_len = strlen_P(FW_VERSION_STR_P());
if (fw_string_len < 6) {
MENU_ITEM(back, PSTR(MSG_FW_VERSION " - " FW_version), lcd_main_menu);
} else {
MENU_ITEM(back, PSTR("FW - " FW_version), lcd_main_menu);
}
MENU_ITEM(back, MSG_PRUSA3D, lcd_main_menu);
MENU_ITEM(back, MSG_PRUSA3D_FORUM, lcd_main_menu);
MENU_ITEM(back, MSG_PRUSA3D_HOWTO, lcd_main_menu);
@ -1324,6 +1333,20 @@ void lcd_show_fullscreen_message_and_wait_P(const char *msg)
}
}
void lcd_wait_for_click()
{
for (;;) {
manage_heater();
manage_inactivity(true);
if (lcd_clicked()) {
while (lcd_clicked()) ;
delay(10);
while (lcd_clicked()) ;
return;
}
}
}
int8_t lcd_show_fullscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting)
{
lcd_display_message_fullscreen_P(msg);

View File

@ -39,6 +39,7 @@
static void lcd_menu_statistics();
extern void lcd_display_message_fullscreen_P(const char *msg);
extern void lcd_wait_for_click();
extern void lcd_show_fullscreen_message_and_wait_P(const char *msg);
// 0: no, 1: yes, -1: timeouted
extern int8_t lcd_show_fullscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting = true);
@ -173,6 +174,7 @@ char *ftostr52(const float &x);
extern void lcd_implementation_clear();
extern void lcd_printPGM(const char* str);
extern void lcd_print_at_PGM(uint8_t x, uint8_t y, const char* str);
extern void lcd_implementation_write(char c);
extern void lcd_implementation_print(const char *str);
extern void lcd_implementation_print(int8_t i);
extern void lcd_implementation_print_at(uint8_t x, uint8_t y, int8_t i);

View File

@ -591,6 +591,11 @@ void lcd_print_at_PGM(uint8_t x, uint8_t y, const char* str)
}
}
void lcd_implementation_write(char c)
{
lcd.write(c);
}
void lcd_implementation_print(int8_t i)
{
lcd.print(i);

279
Firmware/util.cpp Normal file
View File

@ -0,0 +1,279 @@
#include "Configuration.h"
#include "ultralcd.h"
#include "language.h"
// Allocate the version string in the program memory. Otherwise the string lands either on the stack or in the global RAM.
const char FW_VERSION_STR[] PROGMEM = FW_version;
const char* FW_VERSION_STR_P()
{
return FW_VERSION_STR;
}
enum RevisionType
{
REVISION_DEV = 0,
REVISION_ALPHA = 1,
REVISION_BETA = 2,
REVISION_RC,
REVISION_RC2,
REVISION_RC3,
REVISION_RC4,
REVISION_RC5,
REVISION_RELEASED = 127
};
const char STR_REVISION_DEV [] PROGMEM = "dev";
const char STR_REVISION_ALPHA[] PROGMEM = "alpha";
const char STR_REVISION_BETA [] PROGMEM = "beta";
const char STR_REVISION_RC [] PROGMEM = "rc";
inline bool is_whitespace_or_nl(char c)
{
return c == ' ' || c == '\t' || c == '\n' || c == 'r';
}
inline bool is_whitespace_or_nl_or_eol(char c)
{
return c == 0 || c == ' ' || c == '\t' || c == '\n' || c == '\r';
}
inline bool is_digit(char c)
{
return c >= '0' && c <= '9';
}
// Parse a major.minor.revision version number.
// Return true if valid.
inline bool parse_version(const char *str, uint16_t version[4])
{
#if 0
SERIAL_ECHOPGM("Parsing version string ");
SERIAL_ECHO(str);
SERIAL_ECHOLNPGM("");
#endif
const char *major = str;
const char *p = str;
while (is_digit(*p)) ++ p;
if (*p != '.')
return false;
const char *minor = ++ p;
while (is_digit(*p)) ++ p;
if (*p != '.')
return false;
const char *rev = ++ p;
while (is_digit(*p)) ++ p;
if (! is_whitespace_or_nl_or_eol(*p) && *p != '-')
return false;
char *endptr = NULL;
version[0] = strtol(major, &endptr, 10);
if (endptr != minor - 1)
return false;
version[1] = strtol(minor, &endptr, 10);
if (endptr != rev - 1)
return false;
version[2] = strtol(rev, &endptr, 10);
if (endptr != p)
return false;
version[3] = REVISION_RELEASED;
if (*p ++ == '-') {
const char *q = p;
while (! is_whitespace_or_nl_or_eol(*q))
++ q;
uint8_t n = q - p;
if (n == strlen_P(STR_REVISION_DEV) && strncmp_P(p, STR_REVISION_DEV, n) == 0)
version[3] = REVISION_DEV;
else if (n == strlen_P(STR_REVISION_ALPHA) && strncmp_P(p, STR_REVISION_ALPHA, n) == 0)
version[3] = REVISION_ALPHA;
else if (n == strlen_P(STR_REVISION_BETA) && strncmp_P(p, STR_REVISION_BETA, n) == 0)
version[3] = REVISION_BETA;
else if ((n == 2 || n == 3) && p[0] == 'r' && p[1] == 'c') {
if (n == 2)
version[3] = REVISION_RC;
else {
if (is_digit(p[2]))
version[3] = REVISION_RC + p[2] - '1';
else
return false;
}
} else
return false;
}
#if 0
SERIAL_ECHOPGM("Version parsed, major: ");
SERIAL_ECHO(version[0]);
SERIAL_ECHOPGM(", minor: ");
SERIAL_ECHO(version[1]);
SERIAL_ECHOPGM(", revision: ");
SERIAL_ECHO(version[2]);
SERIAL_ECHOPGM(", flavor: ");
SERIAL_ECHO(version[3]);
SERIAL_ECHOLNPGM("");
#endif
return true;
}
inline bool strncmp_PP(const char *p1, const char *p2, uint8_t n)
{
for (; n > 0; -- n, ++ p1, ++ p2) {
if (pgm_read_byte(p1) < pgm_read_byte(p2))
return -1;
if (pgm_read_byte(p1) > pgm_read_byte(p2))
return 1;
if (pgm_read_byte(p1) == 0)
return 0;
}
return 0;
}
// Parse a major.minor.revision version number.
// Return true if valid.
inline bool parse_version_P(const char *str, uint16_t version[4])
{
#if 0
SERIAL_ECHOPGM("Parsing version string ");
SERIAL_ECHORPGM(str);
SERIAL_ECHOLNPGM("");
#endif
const char *major = str;
const char *p = str;
while (is_digit(char(pgm_read_byte(p)))) ++ p;
if (pgm_read_byte(p) != '.')
return false;
const char *minor = ++ p;
while (is_digit(char(pgm_read_byte(p)))) ++ p;
if (pgm_read_byte(p) != '.')
return false;
const char *rev = ++ p;
while (is_digit(char(pgm_read_byte(p)))) ++ p;
if (! is_whitespace_or_nl_or_eol(char(pgm_read_byte(p))) && pgm_read_byte(p) != '-')
return false;
char buf[5];
uint8_t n = minor - major - 1;
if (n > 4)
return false;
memcpy_P(buf, major, n); buf[n] = 0;
char *endptr = NULL;
version[0] = strtol(buf, &endptr, 10);
if (*endptr != 0)
return false;
n = rev - minor - 1;
if (n > 4)
return false;
memcpy_P(buf, minor, n); buf[n] = 0;
version[1] = strtol(buf, &endptr, 10);
if (*endptr != 0)
return false;
n = p - rev;
if (n > 4)
return false;
memcpy_P(buf, rev, n);
buf[n] = 0;
version[2] = strtol(buf, &endptr, 10);
if (*endptr != 0)
return false;
version[3] = REVISION_RELEASED;
if (pgm_read_byte(p ++) == '-') {
const char *q = p;
while (! is_whitespace_or_nl_or_eol(char(pgm_read_byte(q))))
++ q;
n = q - p;
if (n == strlen_P(STR_REVISION_DEV) && strncmp_PP(p, STR_REVISION_DEV, n) == 0)
version[3] = REVISION_DEV;
else if (n == strlen_P(STR_REVISION_ALPHA) && strncmp_PP(p, STR_REVISION_ALPHA, n) == 0)
version[3] = REVISION_ALPHA;
else if (n == strlen_P(STR_REVISION_BETA) && strncmp_PP(p, STR_REVISION_BETA, n) == 0)
version[3] = REVISION_BETA;
else if ((n == 2 || n == 3) && strncmp_PP(p, STR_REVISION_RC, 2) == 0) {
if (n == 2)
version[3] = REVISION_RC;
else {
p += 2;
if (is_digit(pgm_read_byte(p)))
version[3] = REVISION_RC + pgm_read_byte(p) - '1';
else
return false;
}
} else
return false;
}
#if 0
SERIAL_ECHOPGM("Version parsed, major: ");
SERIAL_ECHO(version[0]);
SERIAL_ECHOPGM(", minor: ");
SERIAL_ECHO(version[1]);
SERIAL_ECHOPGM(", revision: ");
SERIAL_ECHO(version[2]);
SERIAL_ECHOPGM(", flavor: ");
SERIAL_ECHO(version[3]);
SERIAL_ECHOLNPGM("");
#endif
return true;
}
// 1 - yes, 0 - false, -1 - error;
inline int8_t is_provided_version_newer(const char *version_string)
{
uint16_t ver_gcode[3], ver_current[3];
if (! parse_version(version_string, ver_gcode))
return -1;
if (! parse_version_P(FW_VERSION_STR, ver_current))
return 0; // this shall not happen
for (uint8_t i = 0; i < 3; ++ i)
if (ver_gcode[i] > ver_current[i])
return 1;
return 0;
}
bool show_upgrade_dialog_if_version_newer(const char *version_string)
{
uint16_t ver_gcode[4], ver_current[4];
if (! parse_version(version_string, ver_gcode)) {
// SERIAL_PROTOCOLLNPGM("parse_version failed");
return false;
}
if (! parse_version_P(FW_VERSION_STR, ver_current)) {
// SERIAL_PROTOCOLLNPGM("parse_version_P failed");
return false; // this shall not happen
}
// SERIAL_PROTOCOLLNPGM("versions parsed");
bool upgrade = false;
for (uint8_t i = 0; i < 4; ++ i) {
if (ver_gcode[i] > ver_current[i]) {
upgrade = true;
break;
} else if (ver_gcode[i] < ver_current[i])
break;
}
if (upgrade) {
lcd_display_message_fullscreen_P(MSG_NEW_FIRMWARE_AVAILABLE);
lcd_print_at_PGM(0, 2, PSTR(""));
for (const char *c = version_string; ! is_whitespace_or_nl_or_eol(*c); ++ c)
lcd_implementation_write(*c);
lcd_print_at_PGM(0, 3, MSG_NEW_FIRMWARE_PLEASE_UPGRADE);
tone(BEEPER, 1000);
delay_keep_alive(50);
noTone(BEEPER);
delay_keep_alive(500);
tone(BEEPER, 1000);
delay_keep_alive(50);
noTone(BEEPER);
lcd_wait_for_click();
lcd_update_enable(true);
lcd_implementation_clear();
lcd_update();
}
// Succeeded.
return true;
}

8
Firmware/util.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef UTIL_H
#define UTIL_H
extern const char* FW_VERSION_STR_P();
extern bool show_upgrade_dialog_if_version_newer(const char *version_string);
#endif /* UTIL_H */