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:
parent
d7c75f2060
commit
0b372bfc94
@ -61,6 +61,7 @@
|
|||||||
#include "language.h"
|
#include "language.h"
|
||||||
#include "pins_arduino.h"
|
#include "pins_arduino.h"
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
#ifdef BLINKM
|
#ifdef BLINKM
|
||||||
#include "BlinkM.h"
|
#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 float code_value() { return strtod(strchr_pointer+1, NULL); }
|
||||||
static inline long code_value_long() { return strtol(strchr_pointer+1, NULL, 10); }
|
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 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) \
|
#define DEFINE_PGM_READ_ANY(type, reader) \
|
||||||
static inline type pgm_read_any(const type *p) \
|
static inline type pgm_read_any(const type *p) \
|
||||||
@ -2766,7 +2768,7 @@ void process_commands()
|
|||||||
}
|
}
|
||||||
break;
|
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 the skew and offset in both RAM and EEPROM.
|
||||||
reset_bed_offset_and_skew();
|
reset_bed_offset_and_skew();
|
||||||
// Reset world2machine_rotation_and_skew and world2machine_shift, therefore
|
// Reset world2machine_rotation_and_skew and world2machine_shift, therefore
|
||||||
@ -2775,7 +2777,7 @@ void process_commands()
|
|||||||
world2machine_revert_to_uncorrected();
|
world2machine_revert_to_uncorrected();
|
||||||
break;
|
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.
|
// Disable the default update procedure of the display. We will do a modal dialog.
|
||||||
lcd_update_enable(false);
|
lcd_update_enable(false);
|
||||||
@ -2835,7 +2837,12 @@ void process_commands()
|
|||||||
break;
|
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.
|
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.
|
// Disable the default update procedure of the display. We will do a modal dialog.
|
||||||
@ -2874,10 +2881,6 @@ void process_commands()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case 47:
|
|
||||||
lcd_diag_show_end_stops();
|
|
||||||
break;
|
|
||||||
|
|
||||||
// M48 Z-Probe repeatability measurement function.
|
// 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>
|
// 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;
|
break;
|
||||||
case 115: // M115
|
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;
|
break;
|
||||||
case 117: // M117 display message
|
case 117: // M117 display message
|
||||||
starpos = (strchr(strchr_pointer + 5,'*'));
|
starpos = (strchr(strchr_pointer + 5,'*'));
|
||||||
|
@ -1760,6 +1760,32 @@ const char * const MSG_MOVE_Z_LANG_TABLE[LANG_NUM] PROGMEM = {
|
|||||||
MSG_MOVE_Z_PL
|
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_EN[] PROGMEM = "No";
|
||||||
const char MSG_NO_CZ[] PROGMEM = "Ne";
|
const char MSG_NO_CZ[] PROGMEM = "Ne";
|
||||||
const char MSG_NO_IT[] PROGMEM = "No";
|
const char MSG_NO_IT[] PROGMEM = "No";
|
||||||
|
@ -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)
|
#define MSG_MOVE_Y LANG_TABLE_SELECT(MSG_MOVE_Y_LANG_TABLE)
|
||||||
extern const char* const MSG_MOVE_Z_LANG_TABLE[LANG_NUM];
|
extern const char* const MSG_MOVE_Z_LANG_TABLE[LANG_NUM];
|
||||||
#define MSG_MOVE_Z LANG_TABLE_SELECT(MSG_MOVE_Z_LANG_TABLE)
|
#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];
|
extern const char* const MSG_NO_LANG_TABLE[LANG_NUM];
|
||||||
#define MSG_NO LANG_TABLE_SELECT(MSG_NO_LANG_TABLE)
|
#define MSG_NO LANG_TABLE_SELECT(MSG_NO_LANG_TABLE)
|
||||||
extern const char* const MSG_NOT_COLOR_LANG_TABLE[LANG_NUM];
|
extern const char* const MSG_NOT_COLOR_LANG_TABLE[LANG_NUM];
|
||||||
|
@ -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_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_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
|
#endif // LANGUAGE_EN_H
|
||||||
|
@ -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_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_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
|
#endif // LANGUAGE_EN_H
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
#include "stepper.h"
|
#include "stepper.h"
|
||||||
#include "ConfigurationStore.h"
|
#include "ConfigurationStore.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
//#include "Configuration.h"
|
//#include "Configuration.h"
|
||||||
|
|
||||||
|
|
||||||
@ -659,7 +661,14 @@ static void lcd_support_menu()
|
|||||||
|
|
||||||
MENU_ITEM(back, MSG_MAIN, lcd_main_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, lcd_main_menu);
|
||||||
MENU_ITEM(back, MSG_PRUSA3D_FORUM, lcd_main_menu);
|
MENU_ITEM(back, MSG_PRUSA3D_FORUM, lcd_main_menu);
|
||||||
MENU_ITEM(back, MSG_PRUSA3D_HOWTO, 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)
|
int8_t lcd_show_fullscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting)
|
||||||
{
|
{
|
||||||
lcd_display_message_fullscreen_P(msg);
|
lcd_display_message_fullscreen_P(msg);
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
static void lcd_menu_statistics();
|
static void lcd_menu_statistics();
|
||||||
|
|
||||||
extern void lcd_display_message_fullscreen_P(const char *msg);
|
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);
|
extern void lcd_show_fullscreen_message_and_wait_P(const char *msg);
|
||||||
// 0: no, 1: yes, -1: timeouted
|
// 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);
|
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_implementation_clear();
|
||||||
extern void lcd_printPGM(const char* str);
|
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_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(const char *str);
|
||||||
extern void lcd_implementation_print(int8_t i);
|
extern void lcd_implementation_print(int8_t i);
|
||||||
extern void lcd_implementation_print_at(uint8_t x, uint8_t y, int8_t i);
|
extern void lcd_implementation_print_at(uint8_t x, uint8_t y, int8_t i);
|
||||||
|
@ -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)
|
void lcd_implementation_print(int8_t i)
|
||||||
{
|
{
|
||||||
lcd.print(i);
|
lcd.print(i);
|
||||||
|
279
Firmware/util.cpp
Normal file
279
Firmware/util.cpp
Normal 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
8
Firmware/util.h
Normal 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 */
|
Loading…
Reference in New Issue
Block a user