Merge branch 'prusa3d:MK3' into lcd-optimisation-gudni
This commit is contained in:
commit
c6ecc0dfc9
8
.github/ISSUE_TEMPLATE/bug_report.md
vendored
8
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -6,14 +6,14 @@ labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Please, before you create a new bug report, please make sure you searched in open and closed issues and couldn't find anything that matches.
|
||||
|
||||
-->
|
||||
**Printer type** - [e.g. MK3S, MK3, MK2.5S, MK2.5, MK2S, MK2]
|
||||
**Printer firmware version** - [e.g. 3.8.1, 3.8.1-RC1, ...]
|
||||
|
||||
**MMU Upgrade** - [e.g. MMU2S, MMU2, MMU1]
|
||||
**MMU upgrade firmware version [e.g. 1.0.6, 1.0.6-RC2, ...]
|
||||
**MMU upgrade** - [e.g. MMU2S, MMU2, MMU1]
|
||||
**MMU upgrade firmware version** - [e.g. 1.0.6, 1.0.6-RC2, ...]
|
||||
|
||||
**SD card or USB/Octoprint**
|
||||
Please let us know if you print via SD card or USB/Octoprint
|
||||
|
17
.github/ISSUE_TEMPLATE/community.md
vendored
Normal file
17
.github/ISSUE_TEMPLATE/community.md
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Community
|
||||
about: Related to "Community made" features
|
||||
title: "[Community made] <Enter comprehensive title>"
|
||||
labels: community_made
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Prusa Research will NOT follow up these issues!
|
||||
The maintainers of the "Community made" feature should/will react.
|
||||
|
||||
Please, before you create a new "Community made" ticket, please make sure you searched in open and closed issues and couldn't find anything that matches.
|
||||
|
||||
**Which Community made feature do you want to address?**
|
||||
|
||||
**What is your request/question/suggestion?**
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,7 +1,9 @@
|
||||
.settings
|
||||
.project
|
||||
.cproject
|
||||
.vscode
|
||||
Debug
|
||||
__pycache__
|
||||
Firmware/Configuration_prusa.h
|
||||
Firmware/Doc
|
||||
/Firmware/.vs/Firmware/v14
|
||||
@ -52,3 +54,5 @@ Firmware/Doc
|
||||
/Firmware/Firmware.vcxproj
|
||||
/Firmware/Configuration_prusa_bckp.h
|
||||
/Firmware/variants/printers.h
|
||||
Configuration.tmp
|
||||
config.tmp
|
||||
|
@ -1,4 +1,4 @@
|
||||
dist: trusty
|
||||
dist: focal
|
||||
before_install:
|
||||
- sudo apt-get install -y ninja-build
|
||||
# Arduino IDE adds a lot of noise caused by network traffic, trying to firewall it off
|
||||
|
36
Community_made.md
Normal file
36
Community_made.md
Normal file
@ -0,0 +1,36 @@
|
||||
# Community made
|
||||
|
||||
## Prusa-Firmware build
|
||||
- `PF-build.sh`
|
||||
- Maintainers: **@3d-gussner**
|
||||
- Co-maintainers:
|
||||
- Contributors: **@mkbel**, **@ropaha**, **@deliopoulos**, **@DRracer**, **wavexx**, **@leptun**, **@andrewluebke**, **@kuhnmarek**
|
||||
- [X] **Active** since February 2019
|
||||
- [X] **Maintained** since January 2019
|
||||
|
||||
### How-to use PF-build.sh
|
||||
Start `./PF-build.sh` and follow the instructions
|
||||
|
||||
Help `./PF-build.sh -h`
|
||||
|
||||
# MK404 Simulator
|
||||
|
||||
## MK404-build.sh
|
||||
**MK404 is a community 3d printer simulator created by @vintagepc**
|
||||
Please checkout and support his github repository [MK404](https://github.com/vintagepc/MK404) and the [MK404 Wiki](https://github.com/vintagepc/MK404/wiki)
|
||||
|
||||
At this moment the `MK404-build.sh` script is only supported on Linux
|
||||
- `MK404-build.sh`
|
||||
- Maintainers: **@3d-gussner**
|
||||
- Co-maintainers:
|
||||
- Contributors:
|
||||
- [X] **Active** since August 2021
|
||||
- [X] **Maintained** since August 2021
|
||||
|
||||
### How-to use MK404-build.sh
|
||||
After compiling with `PF-build.sh` you get the option to start the `MK404` simulator with the fresh compiled firmware. (Linux only at this moment)
|
||||
|
||||
Help `./MK404-build.sh -h`
|
||||
|
||||
## Translations
|
||||
- see [/lang/Community_made_translations.md](https://github.com/prusa3d/Prusa-Firmware/blob/MK3/lang/Community_made_translations.md)
|
@ -18,10 +18,16 @@ extern PGM_P sPrinterName;
|
||||
// Firmware version
|
||||
#define FW_MAJOR 3
|
||||
#define FW_MINOR 10
|
||||
#define FW_REVISION 0
|
||||
#define FW_REVISION 1
|
||||
//#define FW_FLAVOR RC //uncomment if DEBUG, DEVEL, APLHA, BETA or RC
|
||||
//#define FW_FLAVERSION 1 //uncomment if FW_FLAVOR is defined and versioning is needed.
|
||||
#ifndef FW_FLAVOR
|
||||
#define FW_VERSION STR(FW_MAJOR) "." STR(FW_MINOR) "." STR(FW_REVISION)
|
||||
#else
|
||||
#define FW_VERSION STR(FW_MAJOR) "." STR(FW_MINOR) "." STR(FW_REVISION) "-" STR(FW_FLAVOR) "" STR(FW_FLAVERSION)
|
||||
#endif
|
||||
|
||||
#define FW_COMMIT_NR 4481
|
||||
#define FW_COMMIT_NR 4697
|
||||
|
||||
// FW_VERSION_UNKNOWN means this is an unofficial build.
|
||||
// The firmware should only be checked into github with this symbol.
|
||||
|
@ -236,10 +236,12 @@ void update_currents();
|
||||
void get_coordinates();
|
||||
void prepare_move();
|
||||
void kill(const char *full_screen_message = NULL, unsigned char id = 0);
|
||||
void Stop();
|
||||
bool IsStopped();
|
||||
void finishAndDisableSteppers();
|
||||
|
||||
void UnconditionalStop(); // Stop heaters, motion and clear current print status
|
||||
void Stop(); // Emergency stop used by overtemp functions which allows recovery
|
||||
bool IsStopped(); // Returns true if the print has been stopped
|
||||
|
||||
//put an ASCII command at the end of the current buffer, read from flash
|
||||
#define enquecommand_P(cmd) enquecommand(cmd, true)
|
||||
|
||||
|
@ -1011,7 +1011,8 @@ static void fw_crash_init()
|
||||
eeprom_read_byte((uint8_t*)EEPROM_FW_CRASH_FLAG) != 0xFF)
|
||||
{
|
||||
lcd_show_fullscreen_message_and_wait_P(
|
||||
_i("FIRMWARE CRASH!\n"
|
||||
_i("FW crash detected! "
|
||||
"You can continue printing. "
|
||||
"Debug data available for analysis. "
|
||||
"Contact support to submit details."));
|
||||
}
|
||||
@ -6751,7 +6752,7 @@ Sigma_Exit:
|
||||
target_direction = isHeatingBed(); // true if heating, false if cooling
|
||||
|
||||
KEEPALIVE_STATE(NOT_BUSY);
|
||||
while ( (target_direction)&&(!cancel_heatup) ? (isHeatingBed()) : (isCoolingBed()&&(CooldownNoWait==false)) )
|
||||
while ( (!cancel_heatup) && (target_direction ? (isHeatingBed()) : (isCoolingBed()&&(CooldownNoWait==false))) )
|
||||
{
|
||||
if(( _millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up.
|
||||
{
|
||||
@ -6887,7 +6888,7 @@ Sigma_Exit:
|
||||
- `X` - X axis
|
||||
- `Y` - Y axis
|
||||
- `Z` - Z axis
|
||||
- `E` - Exruder
|
||||
- `E` - Extruder
|
||||
|
||||
### M18 - Disable steppers <a href="https://reprap.org/wiki/G-code#M18:_Disable_all_stepper_motors">M18: Disable all stepper motors</a>
|
||||
Equal to M84 (compatibility)
|
||||
@ -8625,7 +8626,7 @@ Sigma_Exit:
|
||||
*/
|
||||
case 910:
|
||||
{
|
||||
tmc2130_init();
|
||||
tmc2130_init(TMCInitParams(false, FarmOrUserECool()));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -8692,7 +8693,7 @@ Sigma_Exit:
|
||||
{
|
||||
tmc2130_mode = TMC2130_MODE_NORMAL;
|
||||
update_mode_profile();
|
||||
tmc2130_init();
|
||||
tmc2130_init(TMCInitParams(false, FarmOrUserECool()));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -8704,7 +8705,7 @@ Sigma_Exit:
|
||||
{
|
||||
tmc2130_mode = TMC2130_MODE_SILENT;
|
||||
update_mode_profile();
|
||||
tmc2130_init();
|
||||
tmc2130_init(TMCInitParams(false, FarmOrUserECool()));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -9329,7 +9330,7 @@ Sigma_Exit:
|
||||
|
||||
#ifdef XFLASH_DUMP
|
||||
/*!
|
||||
### D20 - Generate an offline crash dump
|
||||
### D20 - Generate an offline crash dump <a href="https://reprap.org/wiki/G-code#D20:_Generate_an_offline_crash_dump">D20: Generate an offline crash dump</a>
|
||||
Generate a crash dump for later retrival.
|
||||
#### Usage
|
||||
|
||||
@ -9348,7 +9349,7 @@ Sigma_Exit:
|
||||
};
|
||||
|
||||
/*!
|
||||
### D21 - Print crash dump to serial
|
||||
### D21 - Print crash dump to serial <a href="https://reprap.org/wiki/G-code#D21:_Print_crash_dump_to_serial">D21: Print crash dump to serial</a>
|
||||
Output the complete crash dump (if present) to the serial.
|
||||
#### Usage
|
||||
|
||||
@ -9363,7 +9364,7 @@ Sigma_Exit:
|
||||
};
|
||||
|
||||
/*!
|
||||
### D22 - Clear crash dump state
|
||||
### D22 - Clear crash dump state <a href="https://reprap.org/wiki/G-code#D22:_Clear_crash_dump_state">D22: Clear crash dump state</a>
|
||||
Clear an existing internal crash dump.
|
||||
#### Usage
|
||||
|
||||
@ -9377,7 +9378,7 @@ Sigma_Exit:
|
||||
|
||||
#ifdef EMERGENCY_SERIAL_DUMP
|
||||
/*!
|
||||
### D23 - Request emergency dump on serial
|
||||
### D23 - Request emergency dump on serial <a href="https://reprap.org/wiki/G-code#D23:_Request_emergency_dump_on_serial">D23: Request emergency dump on serial</a>
|
||||
On boards without offline dump support, request online dumps to the serial port on firmware faults.
|
||||
When online dumps are enabled, the FW will dump memory on the serial before resetting.
|
||||
#### Usage
|
||||
@ -10157,6 +10158,32 @@ void kill(const char *full_screen_message, unsigned char id)
|
||||
} // Wait for reset
|
||||
}
|
||||
|
||||
void UnconditionalStop()
|
||||
{
|
||||
CRITICAL_SECTION_START;
|
||||
|
||||
// Disable all heaters and unroll the temperature wait loop stack
|
||||
disable_heater();
|
||||
cancel_heatup = true;
|
||||
|
||||
// Clear any saved printing state
|
||||
cancel_saved_printing();
|
||||
|
||||
// Abort the planner
|
||||
planner_abort_hard();
|
||||
|
||||
// Reset the queue
|
||||
cmdqueue_reset();
|
||||
cmdqueue_serial_disabled = false;
|
||||
|
||||
// Reset the sd status
|
||||
card.sdprinting = false;
|
||||
card.closefile();
|
||||
|
||||
st_reset_timer();
|
||||
CRITICAL_SECTION_END;
|
||||
}
|
||||
|
||||
// Stop: Emergency stop used by overtemp functions which allows recovery
|
||||
//
|
||||
// In addition to stopping the print, this prevents subsequent G[0-3] commands to be
|
||||
@ -10169,15 +10196,27 @@ void kill(const char *full_screen_message, unsigned char id)
|
||||
// the addition of disabling the headers) could allow true recovery in the future.
|
||||
void Stop()
|
||||
{
|
||||
// Keep disabling heaters
|
||||
disable_heater();
|
||||
|
||||
// Call the regular stop function if that's the first time during a new print
|
||||
if(Stopped == false) {
|
||||
Stopped = true;
|
||||
lcd_print_stop();
|
||||
Stopped_gcode_LastN = gcode_LastN; // Save last g_code for restart
|
||||
|
||||
// Eventually report the stopped status (though this is usually overridden by a
|
||||
// higher-priority alert status message)
|
||||
SERIAL_ERROR_START;
|
||||
SERIAL_ERRORLNRPGM(MSG_ERR_STOPPED);
|
||||
LCD_MESSAGERPGM(_T(MSG_STOPPED));
|
||||
}
|
||||
|
||||
// Return to the status screen to stop any pending menu action which could have been
|
||||
// started by the user while stuck in the Stopped state. This also ensures the NEW
|
||||
// error is immediately shown.
|
||||
if (menu_menu != lcd_status_screen)
|
||||
lcd_return_to_status();
|
||||
}
|
||||
|
||||
bool IsStopped() { return Stopped; };
|
||||
|
@ -1030,7 +1030,6 @@ void CardReader::presort() {
|
||||
|
||||
lcd_update(2);
|
||||
KEEPALIVE_STATE(NOT_BUSY);
|
||||
lcd_timeoutToStatus.start();
|
||||
}
|
||||
|
||||
void CardReader::flush_presort() {
|
||||
|
@ -1381,33 +1381,15 @@ void temp_runaway_check(int _heater_id, float _target_temperature, float _curren
|
||||
|
||||
void temp_runaway_stop(bool isPreheat, bool isBed)
|
||||
{
|
||||
cancel_heatup = true;
|
||||
quickStop();
|
||||
if (card.sdprinting)
|
||||
{
|
||||
card.sdprinting = false;
|
||||
card.closefile();
|
||||
}
|
||||
// Clean the input command queue
|
||||
// This is necessary, because in command queue there can be commands which would later set heater or bed temperature.
|
||||
cmdqueue_reset();
|
||||
|
||||
disable_heater();
|
||||
disable_x();
|
||||
disable_y();
|
||||
disable_e0();
|
||||
disable_e1();
|
||||
disable_e2();
|
||||
manage_heater();
|
||||
lcd_update(0);
|
||||
Sound_MakeCustom(200,0,true);
|
||||
|
||||
if (isPreheat)
|
||||
{
|
||||
Stop();
|
||||
isBed ? LCD_ALERTMESSAGEPGM("BED PREHEAT ERROR") : LCD_ALERTMESSAGEPGM("PREHEAT ERROR");
|
||||
lcd_setalertstatuspgm(isBed? PSTR("BED PREHEAT ERROR") : PSTR("PREHEAT ERROR"), LCD_STATUS_CRITICAL);
|
||||
SERIAL_ERROR_START;
|
||||
isBed ? SERIAL_ERRORLNPGM(" THERMAL RUNAWAY (PREHEAT HEATBED)") : SERIAL_ERRORLNPGM(" THERMAL RUNAWAY (PREHEAT HOTEND)");
|
||||
|
||||
#ifdef EXTRUDER_ALTFAN_DETECT
|
||||
altfanStatus.altfanOverride = 1; //full speed
|
||||
#endif //EXTRUDER_ALTFAN_DETECT
|
||||
@ -1418,16 +1400,16 @@ void temp_runaway_stop(bool isPreheat, bool isBed)
|
||||
#else //FAN_SOFT_PWM
|
||||
analogWrite(FAN_PIN, 255);
|
||||
#endif //FAN_SOFT_PWM
|
||||
|
||||
fanSpeed = 255;
|
||||
delayMicroseconds(2000);
|
||||
}
|
||||
else
|
||||
{
|
||||
isBed ? LCD_ALERTMESSAGEPGM("BED THERMAL RUNAWAY") : LCD_ALERTMESSAGEPGM("THERMAL RUNAWAY");
|
||||
lcd_setalertstatuspgm(isBed? PSTR("BED THERMAL RUNAWAY") : PSTR("THERMAL RUNAWAY"), LCD_STATUS_CRITICAL);
|
||||
SERIAL_ERROR_START;
|
||||
isBed ? SERIAL_ERRORLNPGM(" HEATBED THERMAL RUNAWAY") : SERIAL_ERRORLNPGM(" HOTEND THERMAL RUNAWAY");
|
||||
}
|
||||
|
||||
Stop();
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1483,13 +1465,12 @@ uint8_t last_alert_sent_to_lcd = LCDALERT_NONE;
|
||||
|
||||
//! update the current temperature error message
|
||||
//! @param type short error abbreviation (PROGMEM)
|
||||
//! @param func optional lcd update function (lcd_setalertstatus when first setting the error)
|
||||
void temp_update_messagepgm(const char* PROGMEM type, void (*func)(const char*) = lcd_updatestatus)
|
||||
void temp_update_messagepgm(const char* PROGMEM type)
|
||||
{
|
||||
char msg[LCD_WIDTH];
|
||||
strcpy_P(msg, PSTR("Err: "));
|
||||
strcat_P(msg, type);
|
||||
(*func)(msg);
|
||||
lcd_setalertstatus(msg, LCD_STATUS_CRITICAL);
|
||||
}
|
||||
|
||||
//! signal a temperature error on both the lcd and serial
|
||||
@ -1497,7 +1478,7 @@ void temp_update_messagepgm(const char* PROGMEM type, void (*func)(const char*)
|
||||
//! @param e optional extruder index for hotend errors
|
||||
void temp_error_messagepgm(const char* PROGMEM type, uint8_t e = EXTRUDERS)
|
||||
{
|
||||
temp_update_messagepgm(type, lcd_setalertstatus);
|
||||
temp_update_messagepgm(type);
|
||||
|
||||
SERIAL_ERROR_START;
|
||||
|
||||
|
@ -220,7 +220,7 @@ FORCE_INLINE bool isCoolingBed() {
|
||||
#define CHECK_ALL_HEATERS (checkAllHotends()||(target_temperature_bed!=0))
|
||||
|
||||
int getHeaterPower(int heater);
|
||||
void disable_heater();
|
||||
void disable_heater(); // Disable all heaters
|
||||
void updatePID();
|
||||
|
||||
|
||||
|
@ -1399,7 +1399,6 @@ static void lcd_cooldown()
|
||||
setAllTargetHotends(0);
|
||||
setTargetBed(0);
|
||||
fanSpeed = 0;
|
||||
eFilamentAction = FilamentAction::None;
|
||||
lcd_return_to_status();
|
||||
}
|
||||
|
||||
@ -2317,8 +2316,10 @@ void mFilamentItem(uint16_t nTemp, uint16_t nTempBed)
|
||||
}
|
||||
}
|
||||
|
||||
if (bFilamentWaitingFlag) {
|
||||
lcd_set_cursor(0, 0);
|
||||
lcdui_print_temp(LCD_STR_THERMOMETER[0], (int) degHotend(0), (int) degTargetHotend(0));
|
||||
}
|
||||
|
||||
if (lcd_clicked())
|
||||
{
|
||||
@ -6999,22 +7000,9 @@ void lcd_print_stop()
|
||||
if (!card.sdprinting) {
|
||||
SERIAL_ECHOLNRPGM(MSG_OCTOPRINT_CANCEL); // for Octoprint
|
||||
}
|
||||
cmdqueue_serial_disabled = false; //for when canceling a print with a fancheck
|
||||
|
||||
CRITICAL_SECTION_START;
|
||||
|
||||
// Clear any saved printing state
|
||||
cancel_saved_printing();
|
||||
|
||||
// Abort the planner/queue/sd
|
||||
planner_abort_hard();
|
||||
cmdqueue_reset();
|
||||
card.sdprinting = false;
|
||||
card.closefile();
|
||||
st_reset_timer();
|
||||
|
||||
CRITICAL_SECTION_END;
|
||||
UnconditionalStop();
|
||||
|
||||
// TODO: all the following should be moved in the main marlin loop!
|
||||
#ifdef MESH_BED_LEVELING
|
||||
mbl.active = false; //also prevents undoing the mbl compensation a second time in the second planner_abort_hard()
|
||||
#endif
|
||||
@ -7025,11 +7013,11 @@ void lcd_print_stop()
|
||||
pause_time = 0;
|
||||
save_statistics(total_filament_used, t);
|
||||
|
||||
// reset current command
|
||||
lcd_commands_step = 0;
|
||||
lcd_commands_type = LcdCommands::Idle;
|
||||
|
||||
lcd_cooldown(); //turns off heaters and fan; goes to status screen.
|
||||
cancel_heatup = true; //unroll temperature wait loop stack.
|
||||
|
||||
current_position[Z_AXIS] += 10; //lift Z.
|
||||
plan_buffer_line_curposXYZE(manual_feedrate[Z_AXIS] / 60);
|
||||
@ -8511,7 +8499,7 @@ static bool check_file(const char* filename) {
|
||||
cmdqueue_serial_disabled = false;
|
||||
card.printingHasFinished();
|
||||
|
||||
strncpy_P(lcd_status_message, _T(WELCOME_MSG), LCD_WIDTH);
|
||||
lcd_setstatuspgm(_T(WELCOME_MSG));
|
||||
lcd_finishstatus();
|
||||
return result;
|
||||
}
|
||||
@ -8718,19 +8706,23 @@ void lcd_updatestatus(const char *message){
|
||||
lcd_draw_update = 1;
|
||||
}
|
||||
|
||||
void lcd_setalertstatuspgm(const char* message)
|
||||
void lcd_setalertstatuspgm(const char* message, uint8_t severity)
|
||||
{
|
||||
lcd_setstatuspgm(message);
|
||||
lcd_status_message_level = 1;
|
||||
if (severity > lcd_status_message_level) {
|
||||
lcd_updatestatuspgm(message);
|
||||
lcd_status_message_level = severity;
|
||||
lcd_return_to_status();
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_setalertstatus(const char* message)
|
||||
void lcd_setalertstatus(const char* message, uint8_t severity)
|
||||
{
|
||||
lcd_setstatus(message);
|
||||
lcd_status_message_level = 1;
|
||||
if (severity > lcd_status_message_level) {
|
||||
lcd_updatestatus(message);
|
||||
lcd_status_message_level = severity;
|
||||
lcd_return_to_status();
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_reset_alert_level()
|
||||
{
|
||||
@ -8836,6 +8828,7 @@ void menu_lcd_lcdupdate_func(void)
|
||||
LCD_MESSAGERPGM(_T(WELCOME_MSG));
|
||||
bMain=false; // flag (i.e. 'fake parameter') for 'lcd_sdcard_menu()' function
|
||||
menu_submenu(lcd_sdcard_menu);
|
||||
lcd_timeoutToStatus.start();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -11,13 +11,20 @@ extern void menu_lcd_lcdupdate_func(void);
|
||||
void ultralcd_init();
|
||||
void lcd_setstatus(const char* message);
|
||||
void lcd_setstatuspgm(const char* message);
|
||||
|
||||
//! LCD status severities
|
||||
#define LCD_STATUS_CRITICAL 2 //< Heater failure
|
||||
#define LCD_STATUS_ALERT 1 //< Other hardware issue
|
||||
#define LCD_STATUS_NONE 0 //< No alert message set
|
||||
|
||||
//! return to the main status screen and display the alert message
|
||||
//! Beware - it has sideeffects:
|
||||
//! - always returns the display to the main status screen
|
||||
//! - always makes lcd_reset (which is slow and causes flicker)
|
||||
//! - does not update the message if there is already one (i.e. lcd_status_message_level > 0)
|
||||
void lcd_setalertstatus(const char* message);
|
||||
void lcd_setalertstatuspgm(const char* message);
|
||||
//! - does not update the message if there is one with the same (or higher) severity present
|
||||
void lcd_setalertstatus(const char* message, uint8_t severity = LCD_STATUS_ALERT);
|
||||
void lcd_setalertstatuspgm(const char* message, uint8_t severity = LCD_STATUS_ALERT);
|
||||
|
||||
//! only update the alert message on the main status screen
|
||||
//! has no sideeffects, may be called multiple times
|
||||
void lcd_updatestatus(const char *message);
|
||||
|
546
MK404-build.sh
Executable file
546
MK404-build.sh
Executable file
@ -0,0 +1,546 @@
|
||||
#!/bin/bash
|
||||
# This bash script is used to compile automatically and run the MK404 simulator
|
||||
#
|
||||
# Supported OS: Linux64 bit
|
||||
#
|
||||
# Linux:
|
||||
# Linux Ubuntu
|
||||
# 1. Follow these instructions
|
||||
# 2. Open Ubuntu bash and get latest updates with 'sudo apt-get update'
|
||||
# 3. Install latest updates with 'sudo apt-get upgrade'
|
||||
#
|
||||
#
|
||||
# Version: 1.0.0-Build_13
|
||||
# Change log:
|
||||
# 11 Feb 2021, 3d-gussner, Inital
|
||||
# 11 Feb 2021, 3d-gussner, Optional flags to check for updates
|
||||
# 12 Feb 2021, 3d-gussner, Update cmake
|
||||
# 13 Feb 2021, 3d-gussner, Auto build SD cards
|
||||
# 18 Jun 2021, 3d-gussner, Documentation and version number
|
||||
# 18 Jun 2021, 3d-gussner, Added some arguments and checks
|
||||
# 18 Jun 2021, 3d-gussner, Default extrusion graphics to line. Thanks @vintagepc point it out
|
||||
# 18 Jun 2021, 3d-gussner, Added -g 3 and 4 for more details extrusion lines
|
||||
# 18 Jun 2021, 3d-gussner, Check for updates is default. Fix update if internet connection is lost.
|
||||
# 21 Jun 2021, 3d-gussner, Change board_flash argument to 'y' and firmware_version to 'f'
|
||||
|
||||
#### Start: Failures
|
||||
failures()
|
||||
{
|
||||
case "$1" in
|
||||
0) echo "$(tput setaf 2)MK404-build.sh finished with success$(tput sgr0)" ;;
|
||||
2) echo "$(tput setaf 1)Unsupported OS: Linux $(uname -m)" ; echo "Please refer to the notes of MK404-build.sh$(tput sgr0)" ; exit 2 ;;
|
||||
3) echo "$(tput setaf 1)This script doesn't support your Operating system!"; echo "Please use Linux 64-bit"; echo "Read the notes of MK404-build.sh$(tput sgr0)" ; exit 2 ;;
|
||||
4) echo "$(tput setaf 1)Some packages are missing please install these!$(tput sgr0)" ; exit 4 ;;
|
||||
5) echo "$(tput setaf 1)Wrong printer chosen.$(tput sgr0) Following Printers are supported: MK25, MK25S, MK3 and MK3S" ; exit 5 ;;
|
||||
6) echo "$(tput setaf 1)Unsupported board flash size chosen.$(tput sgr0) Only '256', '384', '512', '1024' and '32M' are allowed." ; exit 6 ;;
|
||||
7) echo "$(tput setaf 1)Unsupported board mem size chosen.$(tput sgr0) Only '8', '16', '32' and '64' are allowed." ; exit 7 ;;
|
||||
8) echo "$(tput setaf 1)No firmware version file selected!$(tput sgr0)" ; echo "Add argument -f with path and hex filename to start MK404" ; exit 8 ;;
|
||||
9) echo "$(tput setaf 1)Tried to determine MK404 printer from hex file, but failed!$(tput sgr0)" ; "Add argument -p with 'MK25', 'MK25S', 'MK3' or 'MK3S' to start MK404" ; exit 9 ;;
|
||||
10) echo "$(tput setaf 1)Missing printer$(tput sgr0)" ; exit 10 ;;
|
||||
esac
|
||||
}
|
||||
#### End: Failures
|
||||
|
||||
#### Start: Check options
|
||||
##check_options()
|
||||
##{
|
||||
while getopts c:f:g:m:n:p:u:x:y:?h flag
|
||||
do
|
||||
case "${flag}" in
|
||||
c) check_flag=${OPTARG};;
|
||||
f) firmware_version_flag=${OPTARG};;
|
||||
g) mk404_graphics_flag=${OPTARG};;
|
||||
h) help_flag=1;;
|
||||
m) mk404_flag=${OPTARG};;
|
||||
n) new_build_flag=${OPTARG};;
|
||||
p) mk404_printer_flag=${OPTARG};;
|
||||
u) update_flag=${OPTARG};;
|
||||
x) board_mem_flag=${OPTARG};;
|
||||
y) board_flash_flag=${OPTARG};;
|
||||
?) help_flag=1;;
|
||||
esac
|
||||
done
|
||||
#Debug echos
|
||||
#echo "c: $check_flag"
|
||||
#echo "f: $firmware_version_flag"
|
||||
#echo "g: $mk404_graphics_flag"
|
||||
#echo "m: $mk404_flag"
|
||||
#echo "n: $new_build_flag"
|
||||
#echo "p: $mk404_printer_flag"
|
||||
#echo "u: $update_flag"
|
||||
#echo "x: $board_mem_flag"
|
||||
#echo "y: $board_flash_flag"
|
||||
|
||||
# '?' 'h' argument usage and help
|
||||
if [ "$help_flag" == "1" ] ; then
|
||||
echo "***************************************"
|
||||
echo "* MK404-build.sh Version: 1.0.0-Build_13 *"
|
||||
echo "***************************************"
|
||||
echo "Arguments:"
|
||||
echo "$(tput setaf 2)-c$(tput sgr0) Check for update"
|
||||
echo "$(tput setaf 2)-f$(tput sgr0) Prusa-Firmware version"
|
||||
echo "$(tput setaf 2)-g$(tput sgr0) Start MK404 graphics"
|
||||
echo "$(tput setaf 2)-h$(tput sgr0) Help"
|
||||
echo "$(tput setaf 2)-m$(tput sgr0) Start MK404 sim"
|
||||
echo "$(tput setaf 2)-n$(tput sgr0) Force new build"
|
||||
echo "$(tput setaf 2)-p$(tput sgr0) MK404 Printer"
|
||||
echo "$(tput setaf 2)-u$(tput sgr0) Update MK404"
|
||||
echo "$(tput setaf 2)-x$(tput sgr0) Board memory size"
|
||||
echo "$(tput setaf 2)-y$(tput sgr0) Board flash size"
|
||||
echo "$(tput setaf 2)-?$(tput sgr0) Help"
|
||||
echo
|
||||
echo "Brief USAGE:"
|
||||
echo " $(tput setaf 2)./MK404-build.sh$(tput sgr0) [-c] [-f] [-g] [-m] [-n] [-p] [-u] [-v] [-x] [-h] [-?]"
|
||||
echo
|
||||
echo " -c : '$(tput setaf 2)0$(tput sgr0)' no, '$(tput setaf 2)1$(tput sgr0)' yes"
|
||||
echo " -f : '$(tput setaf 2)path+file name$(tput sgr0)'"
|
||||
echo " -g : '$(tput setaf 2)0$(tput sgr0)' no, '$(tput setaf 2)1$(tput sgr0)' lite, '$(tput setaf 2)2$(tput sgr0)' fancy, '$(tput setaf 2)3$(tput sgr0)' lite with Quad_HR, '$(tput setaf 2)4$(tput sgr0)' fancy with Quad_HR"
|
||||
echo " -m : '$(tput setaf 2)0$(tput sgr0)' no, '$(tput setaf 2)1$(tput sgr0)' yes '$(tput setaf 2)2$(tput sgr0)' with MMU2"
|
||||
echo " -n : '$(tput setaf 2)0$(tput sgr0)' no, '$(tput setaf 2)1$(tput sgr0)' yes"
|
||||
echo " -p : '$(tput setaf 2)MK25$(tput sgr0)', '$(tput setaf 2)MK25S$(tput sgr0)', '$(tput setaf 2)MK3$(tput sgr0)' or '$(tput setaf 2)MK3S$(tput sgr0)'"
|
||||
echo " -u : '$(tput setaf 2)0$(tput sgr0)' no, '$(tput setaf 2)1$(tput sgr0)' yes '"
|
||||
echo " -x : '$(tput setaf 2)8$(tput sgr0)',$(tput setaf 2)16$(tput sgr0)',$(tput setaf 2)32$(tput sgr0)' or '$(tput setaf 2)64$(tput sgr0)' Kb."
|
||||
echo " -y : '$(tput setaf 2)256$(tput sgr0)','$(tput setaf 2)384$(tput sgr0)','$(tput setaf 2)512$(tput sgr0)','$(tput setaf 2)1024$(tput sgr0)''$(tput setaf 2)32M$(tput sgr0)'"
|
||||
echo
|
||||
echo "Example:"
|
||||
echo " $(tput setaf 2)./MK404-build.sh -f 1$(tput sgr0)"
|
||||
echo " Will force an update and rebuild the MK404 SIM"
|
||||
echo
|
||||
echo " $(tput setaf 2)./MK404-build.sh -m 1 -g 1 -f ../../../../Prusa-Firmware/PF-build-hex/FW3100-Build4481/BOARD_EINSY_1_0a/FW3100-Build4481-1_75mm_MK3S-EINSy10a-E3Dv6full.hex$(tput sgr0)"
|
||||
echo " Will start MK404 with Prusa_MK3S and Prusa-Firmware 3.10.0-Build4481"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#Check MK404 agruments
|
||||
#Set Check for updates as default
|
||||
check_flag=1
|
||||
#Start: Check mk404_printer_flag
|
||||
if [ ! -z $mk404_printer_flag ]; then
|
||||
if [[ "$mk404_printer_flag" == "MK3" || "$mk404_printer_flag" == "MK3S" || "$mk404_printer_flag" == "MK25" || "$mk404_printer_flag" == "MK25S" ]]; then
|
||||
MK404_PRINTER_TEMP=$mk404_printer_flag
|
||||
else
|
||||
failures 5
|
||||
fi
|
||||
fi
|
||||
#End: Check mk404_printer_flag
|
||||
|
||||
#Start: Check if Build is selected with argument '-f'
|
||||
if [ ! -z "$board_flash_flag" ] ; then
|
||||
if [ "$board_flash_flag" == "256" ] ; then
|
||||
BOARD_FLASH="0x3FFFF"
|
||||
echo "Board flash size : $board_flash_flag Kb, $BOARD_FLASH (hex)"
|
||||
elif [ "$board_flash_flag" == "384" ] ; then
|
||||
BOARD_FLASH="0x5FFFF"
|
||||
echo "Board flash size : $board_flash_flag Kb, $BOARD_FLASH (hex)"
|
||||
elif [ "$board_flash_flag" == "512" ] ; then
|
||||
BOARD_FLASH="0x7FFFF"
|
||||
echo "Board flash size : $board_flash_flag Kb, $BOARD_FLASH (hex)"
|
||||
elif [ "$board_flash_flag" == "1024" ] ; then
|
||||
BOARD_FLASH="0xFFFFF"
|
||||
echo "Board flash size : $board_flash_flag Kb, $BOARD_FLASH (hex)"
|
||||
elif [[ "$board_flash_flag" == "32M" || "$board_flash_flag" == "32768" ]] ; then
|
||||
BOARD_FLASH="0x1FFFFFF"
|
||||
echo "Board flash size : 32 Mb, $BOARD_FLASH (hex)"
|
||||
else
|
||||
failures 6
|
||||
fi
|
||||
fi
|
||||
#End: Check if Build is selected with argument '-f'
|
||||
|
||||
#Start: Check if Build is selected with argument '-x'
|
||||
if [ ! -z "$board_mem_flag" ] ; then
|
||||
if [ "$board_mem_flag" == "8" ] ; then
|
||||
BOARD_MEM="0x21FF"
|
||||
echo "Board mem size : $board_mem_flag Kb, $BOARD_MEM (hex)"
|
||||
elif [ "$board_mem_flag" == "16" ] ; then
|
||||
BOARD_MEM="0x3DFF"
|
||||
echo "Board mem size : $board_mem_flag Kb, $BOARD_MEM (hex)"
|
||||
elif [ "$board_mem_flag" == "32" ] ; then
|
||||
BOARD_MEM="0x7DFF"
|
||||
echo "Board mem size : $board_mem_flag Kb, $BOARD_MEM (hex)"
|
||||
elif [ "$board_mem_flag" == "64" ] ; then
|
||||
BOARD_MEM="0xFFFF"
|
||||
echo "Board mem size : $board_mem_flag Kb, $BOARD_MEM (hex)"
|
||||
else
|
||||
failures 7
|
||||
fi
|
||||
fi
|
||||
#End: Check if Build is selected with argument '-x'
|
||||
|
||||
#Start: Check if new build is selected
|
||||
if [ "$new_build_flag" == "1" ]; then
|
||||
check_flag=1
|
||||
update_flag=1
|
||||
fi
|
||||
if [ "$update_flag" == "1" ]; then
|
||||
check_flag=1
|
||||
fi
|
||||
#End: Check if new build is selected
|
||||
|
||||
# Prepare run MK404
|
||||
#Check MK404_Printer
|
||||
if [ ! -z $firmware_version_flag ]; then
|
||||
MK404_PRINTER_TEMP=$(echo $firmware_version_flag | sed 's/\(.*\)\///' | grep 'MK3')
|
||||
if [ ! -z $MK404_PRINTER_TEMP ]; then
|
||||
MK404_PRINTER=MK3
|
||||
fi
|
||||
MK404_PRINTER_TEMP=$(echo $firmware_version_flag | sed 's/\(.*\)\///' | grep 'MK3S')
|
||||
if [ ! -z $MK404_PRINTER_TEMP ]; then
|
||||
MK404_PRINTER=MK3S
|
||||
fi
|
||||
MK404_PRINTER_TEMP=$(echo $firmware_version_flag | sed 's/\(.*\)\///' | grep 'MK25')
|
||||
if [ ! -z $MK404_PRINTER_TEMP ]; then
|
||||
MK404_PRINTER=MK25
|
||||
fi
|
||||
MK404_PRINTER_TEMP=$(echo $firmware_version_flag | sed 's/\(.*\)\///' | grep 'MK25S')
|
||||
if [ ! -z $MK404_PRINTER_TEMP ]; then
|
||||
MK404_PRINTER=MK25S
|
||||
fi
|
||||
else
|
||||
failures 8
|
||||
fi
|
||||
|
||||
if [ -z "$MK404_PRINTER" ]; then
|
||||
failures 9
|
||||
fi
|
||||
|
||||
if [ ! -z $mk404_printer_flag ]; then
|
||||
if [ "$mk404_printer_flag" != "$MK404_PRINTER" ]; then
|
||||
echo "$(tput setaf 3)You defined a different printer type than the firmware!"
|
||||
echo "This can cause unexpected issues.$(tput sgr 0)"
|
||||
echo
|
||||
PS3="Select $(tput setaf 2)printer$(tput sgr 0) you want to use."
|
||||
select which in "$(tput setaf 2)$MK404_PRINTER$(tput sgr 0)" "$mk404_printer_flag"; do
|
||||
case $which in
|
||||
$MK404_PRINTER)
|
||||
echo "Set $MK404_PRINTER as printer"
|
||||
break
|
||||
;;
|
||||
$mk404_printer_flag)
|
||||
echo "Set $(tput setaf 3)$mk404_printer_flag$(tput sgr 0) as printer"
|
||||
echo "$(tput setaf 3)This firmware file isn't correct for this printer!!!$(tput sgr 0)"
|
||||
echo
|
||||
MK404_PRINTER=$mk404_printer_flag
|
||||
read -p "Press Enter to continue."
|
||||
break
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z $MK404_PRINTER ]; then
|
||||
failures 10
|
||||
fi
|
||||
|
||||
if [[ "$MK404_PRINTER" == "MK25" || "$MK404_PRINTER" == "MK25S" ]]; then
|
||||
MK404_PRINTER="${MK404_PRINTER}_mR13"
|
||||
else
|
||||
if [ "$mk404_flag" == "2" ]; then # Check if MMU2 is selected only for MK3/S
|
||||
MK404_PRINTER="${MK404_PRINTER}MMU2"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Run MK404 with 'debugcore' and/or 'bootloader-file'
|
||||
if [[ ! -z $MK404_DEBUG && "$MK404_DEBUG" == "atmega404" || ! -z $BOARD_MEM && "$BOARD_MEM" == "0xFFFF" ]]; then
|
||||
MK404_options="--debugcore"
|
||||
fi
|
||||
if [[ ! -z $MK404_DEBUG && "$MK404_DEBUG" == "atmega404_no_bootloader" || ! -z $BOARD_FLASH && "$BOARD_FLASH" != "0x3FFFF" ]]; then
|
||||
MK404_options='--debugcore --bootloader-file ""'
|
||||
fi
|
||||
|
||||
# Run MK404 with graphics
|
||||
if [ ! -z "$mk404_graphics_flag" ]; then
|
||||
if [ ! -z "$MK404_options" ]; then
|
||||
MK404_options="${MK404_options} -g "
|
||||
else
|
||||
MK404_options=" -g "
|
||||
fi
|
||||
if [[ "$mk404_graphics_flag" == "1" || "$mk404_graphics_flag" == "lite" || "$mk404_graphics_flag" == "3" ]]; then
|
||||
MK404_options="${MK404_options}lite"
|
||||
elif [[ "$mk404_graphics_flag" == "2" || "$mk404_graphics_flag" == "fancy" || "$mk404_graphics_flag" == "4" ]]; then
|
||||
MK404_options="${MK404_options}fancy"
|
||||
else
|
||||
echo "$(tput setaf 1)Unsupported MK404 graphics option $mk404_graphics_flag$(tput sgr 0)"
|
||||
fi
|
||||
if [[ "$mk404_graphics_flag" == "3" || "$mk404_graphics_flag" == "4" ]]; then
|
||||
MK404_options="${MK404_options} --colour-extrusion --extrusion Quad_HR"
|
||||
else
|
||||
MK404_options="${MK404_options} --extrusion Line"
|
||||
fi
|
||||
fi
|
||||
if [ ! -z $firmware_version_flag ]; then
|
||||
MK404_firmware_file=" -f $firmware_version_flag"
|
||||
fi
|
||||
|
||||
#End: Check MK404 agruments
|
||||
##}
|
||||
#### End: Check for options/flags
|
||||
|
||||
#### Start: Check if OSTYPE is supported
|
||||
check_OS()
|
||||
{
|
||||
OS_FOUND=$( command -v uname)
|
||||
case $( "${OS_FOUND}" | tr '[:upper:]' '[:lower:]') in
|
||||
linux*)
|
||||
TARGET_OS="linux"
|
||||
;;
|
||||
*)
|
||||
TARGET_OS='unknown'
|
||||
;;
|
||||
esac
|
||||
# Linux
|
||||
if [ $TARGET_OS == "linux" ]; then
|
||||
if [ $(uname -m) == "x86_64" ]; then
|
||||
echo "$(tput setaf 2)Linux 64-bit found$(tput sgr0)"
|
||||
Processor="64"
|
||||
#elif [[ $(uname -m) == "i386" || $(uname -m) == "i686" ]]; then
|
||||
# echo "$(tput setaf 2)Linux 32-bit found$(tput sgr0)"
|
||||
# Processor="32"
|
||||
else
|
||||
failures 2
|
||||
fi
|
||||
else
|
||||
failures 3
|
||||
fi
|
||||
sleep 2
|
||||
}
|
||||
#### End: Check if OSTYPE is supported
|
||||
|
||||
#### Start: Check MK404 dependencies
|
||||
check_packages()
|
||||
{
|
||||
packages=(
|
||||
"libelf-dev"
|
||||
"gcc-7"
|
||||
"gcc-avr"
|
||||
"libglew-dev"
|
||||
"freeglut3-dev"
|
||||
"libsdl-sound1.2-dev"
|
||||
"libpng-dev"
|
||||
"cmake"
|
||||
"zip"
|
||||
"wget"
|
||||
"git"
|
||||
"build-essential"
|
||||
"lcov"
|
||||
"mtools"
|
||||
)
|
||||
|
||||
for check_package in ${packages[@]}; do
|
||||
if dpkg-query -W -f'${db:Status-Abbrev}\n' $check_package 2>/dev/null \
|
||||
| grep -q '^.i $'; then
|
||||
echo "$(tput setaf 2)$check_package: Installed$(tput sgr0)"
|
||||
else
|
||||
echo "$(tput setaf 1)$check_package: Not installed use $(tput setaf 3)'sudo apt install $check_package'$(tput setaf 1) to install missing package$(tput sgr0)"
|
||||
not_installed=1;
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$not_installed" = "1" ]; then
|
||||
failures 4
|
||||
fi
|
||||
}
|
||||
#### End: Check MK404 dependencies
|
||||
|
||||
#### Start: Set build environment
|
||||
set_build_env_variables()
|
||||
{
|
||||
MK404_SCRIPT_PATH="$( cd "$(dirname "$0")" ; pwd -P )"
|
||||
MK404_URL="https://github.com/vintagepc/MK404.git"
|
||||
MK404_owner="vintagepc"
|
||||
MK404_project="MK404"
|
||||
MK404_PATH="$MK404_SCRIPT_PATH/../MK404/master"
|
||||
MK404_BUILD_PATH="$MK404_PATH/build"
|
||||
}
|
||||
#### End: Set build environment
|
||||
|
||||
#### Start: List few useful data
|
||||
output_useful_data()
|
||||
{
|
||||
echo
|
||||
echo "Script path :" $MK404_SCRIPT_PATH
|
||||
echo "OS :" $TARGET_OS
|
||||
echo ""
|
||||
echo "MK404 path :" $MK404_PATH
|
||||
}
|
||||
#### End: List few useful data
|
||||
|
||||
#### Start: Clone MK404 if needed
|
||||
get_MK404()
|
||||
{
|
||||
if [ ! -d $MK404_PATH ]; then
|
||||
#release_url=$(curl -Ls -o /dev/null -w %{url_effective} https://github.com/$MK404_owner/$MK404_project/releases/latest)
|
||||
#release_tag=$(basename $release_url)
|
||||
#git clone -b $release_tag -- https://github.com/$MK404_owner/$MK404_project.git $MK404_PATH
|
||||
git clone $MK404_URL $MK404_PATH
|
||||
fi
|
||||
}
|
||||
#### End: Clone MK404 if needed
|
||||
|
||||
#### Start: Check for updates
|
||||
check_for_updates()
|
||||
{
|
||||
if [ "$check_flag" == "1" ]; then
|
||||
if [ -d $MK404_BUILD_PATH ]; then
|
||||
cd $MK404_BUILD_PATH
|
||||
MK404_current_version=$( command ./MK404 --version | grep "MK404" | cut -f 4 -d " ")
|
||||
cd $MK404_PATH
|
||||
else
|
||||
echo "Cannot check current version as it has not been build."
|
||||
fi
|
||||
# Get local Commit_Hash
|
||||
MK404_local_GIT_COMMIT_HASH=$(git log --pretty=format:"%H" -1)
|
||||
# Get local Commit_Number
|
||||
MK404_local_GIT_COMMIT_NUMBER=$(git rev-list HEAD --count)
|
||||
# Get latest release
|
||||
MK404_release_url=$(curl -Ls -o /dev/null -w %{url_effective} https://github.com/$MK404_owner/$MK404_project/releases/latest)
|
||||
MK404_release_tag=$(basename $MK404_release_url)
|
||||
# Get remote Commit_Hash
|
||||
#MK404_remote_GIT_COMMIT_HASH=$(git ls-remote --heads $(git config --get remote.origin.url) | grep "refs/heads/master" | cut -f 1)
|
||||
MK404_remote_GIT_COMMIT_HASH=$(git ls-remote | grep "refs/tags/$MK404_release_tag" | cut -f 1)
|
||||
# Get remote Commit_Number
|
||||
MK404_remote_GIT_COMMIT_NUMBER=$(git rev-list $MK404_release_tag --count)
|
||||
# Output
|
||||
echo ""
|
||||
echo "Current version : $MK404_current_version"
|
||||
echo ""
|
||||
echo "Current local hash : $MK404_local_GIT_COMMIT_HASH"
|
||||
echo "Current local commit nr : $MK404_local_GIT_COMMIT_NUMBER"
|
||||
if [ "$MK404_local_GIT_COMMIT_HASH" != "$MK404_remote_GIT_COMMIT_HASH" ]; then
|
||||
echo "$(tput setaf 1)"
|
||||
else
|
||||
echo "$(tput setaf 2)"
|
||||
fi
|
||||
echo "Latest release tag : $MK404_release_tag"
|
||||
echo "Latest release hash : $MK404_remote_GIT_COMMIT_HASH"
|
||||
echo "Latest remote commit nr : $MK404_remote_GIT_COMMIT_NUMBER"
|
||||
echo "$(tput sgr 0)"
|
||||
|
||||
# Check for updates
|
||||
if [ ! -z $MK404_remote_GIT_COMMIT_HASH ]; then
|
||||
if [[ "$MK404_local_GIT_COMMIT_HASH" != "$MK404_remote_GIT_COMMIT_HASH" && -z "$update_flag" ]]; then
|
||||
echo "$(tput setaf 2)Update is availible.$(tput sgr 0)"
|
||||
read -t 10 -n 1 -p "$(tput setaf 3)Update now Y/n$(tput sgr 0)" update_answer
|
||||
if [ "$update_answer" == "Y" ]; then
|
||||
update_flag=1
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
#### End: Check for updates
|
||||
|
||||
#### Start: Fetch updates and force new build
|
||||
fetch_updates()
|
||||
{
|
||||
if [ "$update_flag" == "1" ]; then
|
||||
if [ ! -z $MK404_remote_GIT_COMMIT_HASH ]; then
|
||||
if [ "$MK404_local_GIT_COMMIT_HASH" != "$MK404_remote_GIT_COMMIT_HASH" ]; then
|
||||
echo ""
|
||||
git fetch --all
|
||||
read -t 10 -p "$(tput setaf 2)Updating MK404 !$(tput sgr 0)"
|
||||
echo ""
|
||||
git reset --hard $MK404_release_tag
|
||||
read -t 10 -p "$(tput setaf 2)Compiling MK404 !$(tput sgr 0)"
|
||||
echo ""
|
||||
new_build_flag=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
#### End: Fetch updates and force new build
|
||||
|
||||
#### Start: Prepare MK404 build
|
||||
prepare_MK404()
|
||||
{
|
||||
if [ ! -d $MK404_BUILD_PATH ]; then
|
||||
mkdir -p $MK404_BUILD_PATH
|
||||
fi
|
||||
}
|
||||
#### End: Prepare MK404 build
|
||||
|
||||
#### Start: Build MK404
|
||||
build_MK404()
|
||||
{
|
||||
if [[ ! -f "$MK404_BUILD_PATH/Makefile" || "$new_build_flag" == "1" ]]; then
|
||||
# Init and update submodules
|
||||
if [ -d $MK404_BUILD_PATH ]; then
|
||||
rm -rf $MK404_BUILD_PATH
|
||||
mkdir -p $MK404_BUILD_PATH
|
||||
fi
|
||||
git submodule init
|
||||
git submodule update
|
||||
cmake -B$MK404_BUILD_PATH -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles"
|
||||
fi
|
||||
|
||||
# Make MK404
|
||||
cd $MK404_BUILD_PATH
|
||||
if [[ ! -f "$MK404_BUILD_PATH/MK404" || "$new_build_flag" == "1" ]]; then
|
||||
make
|
||||
fi
|
||||
|
||||
# Make SDcards
|
||||
if [[ ! -f "$MK404_BUILD_PATH/Prusa_MK3S_SDcard.bin" || "$new_build_flag" == "1" ]]; then
|
||||
cmake --build $MK404_BUILD_PATH --config Release --target Prusa_MK3S_SDcard.bin
|
||||
cmake --build $MK404_BUILD_PATH --config Release --target Prusa_MK3_SDcard.bin
|
||||
cmake --build $MK404_BUILD_PATH --config Release --target Prusa_MK25_13_SDcard.bin
|
||||
cmake --build $MK404_BUILD_PATH --config Release --target Prusa_MK25S_13_SDcard.bin
|
||||
cmake --build $MK404_BUILD_PATH --config Release --target Prusa_MK3SMMU2_SDcard.bin
|
||||
cmake --build $MK404_BUILD_PATH --config Release --target Prusa_MK3MMU2_SDcard.bin
|
||||
fi
|
||||
}
|
||||
#### End: Build MK404
|
||||
|
||||
|
||||
#### Start: Run MK404 SIM
|
||||
run_MK404_SIM()
|
||||
{
|
||||
if [ ! -z $mk404_flag ]; then
|
||||
# Output some useful data
|
||||
echo "Printer : $MK404_PRINTER"
|
||||
echo "Options : $MK404_options"
|
||||
echo ""
|
||||
read -t 5 -p "Press $(tput setaf 2)Enter$(tput sgr 0) to start MK404"
|
||||
echo ""
|
||||
|
||||
# Change to MK404 build folder
|
||||
cd $MK404_BUILD_PATH
|
||||
|
||||
# Start MK404
|
||||
# default with serial output and terminal to manipulate it via terminal
|
||||
echo ""
|
||||
echo "./MK404 Prusa_$MK404_PRINTER -s --terminal $MK404_options $MK404_firmware_file"
|
||||
sleep 5
|
||||
./MK404 Prusa_$MK404_PRINTER -s --terminal $MK404_options $MK404_firmware_file || exit 10
|
||||
fi
|
||||
}
|
||||
#### End: Run MK404 SIM
|
||||
|
||||
#### Check OS and needed packages
|
||||
echo "Check OS"
|
||||
check_OS
|
||||
check_packages
|
||||
|
||||
#### Check for options/flags
|
||||
echo "Check for options"
|
||||
|
||||
#### Prepare build environment
|
||||
echo "Prepare build env"
|
||||
set_build_env_variables
|
||||
output_useful_data
|
||||
get_MK404
|
||||
|
||||
#
|
||||
cd $MK404_PATH
|
||||
|
||||
check_for_updates
|
||||
fetch_updates
|
||||
prepare_MK404
|
||||
build_MK404
|
||||
run_MK404_SIM
|
||||
#### End of MK404 Simulator
|
1041
PF-build.sh
1041
PF-build.sh
File diff suppressed because it is too large
Load Diff
18
README.md
18
README.md
@ -63,7 +63,7 @@ _Note: Multi language build is not supported._
|
||||
|
||||
**a.** Install `"Arduino Software IDE"` from the official website `https://www.arduino.cc -> Software->Downloads`
|
||||
|
||||
_It is recommended to use version `"1.8.5"`, as it is used on out build server to produce official builds._
|
||||
_It is recommended to use version `"1.8.5"`, as it is used on our build server to produce official builds._
|
||||
|
||||
**b.** Setup Arduino to use Prusa Rambo board definition
|
||||
|
||||
@ -118,7 +118,7 @@ _notes: Script and instructions contributed by 3d-gussner. Use at your own risk.
|
||||
- to install zip run `sudo apt-get install zip`
|
||||
- to install dos2unix run `sudo apt-get install dos2unix`
|
||||
- run `dos2unix PF-build.sh` to convert the windows line endings to unix line endings
|
||||
- add few lines at the top of `~/.bashrc` by running `sudo nano ~/.bashrc`
|
||||
- add a few lines at the top of `~/.bashrc` by running `sudo nano ~/.bashrc`
|
||||
|
||||
export OS="Linux"
|
||||
export JAVA_TOOL_OPTIONS="-Djava.net.preferIPv4Stack=true"
|
||||
@ -134,14 +134,14 @@ _notes: Script and instructions contributed by 3d-gussner. Use at your own risk.
|
||||
- Example: You files are under `C:\Users\<your-username>\Downloads\Prusa-Firmware-MK3`
|
||||
- use under Ubuntu the following command `cd /mnt/c/Users/<your-username>/Downloads/Prusa-Firmware-MK3`
|
||||
to change to the right folder
|
||||
- Unix and windows have different line endings (LF vs CRLF), try dos2unix to convert
|
||||
- Unix and Windows have different line endings (LF vs CRLF), use dos2unix to convert
|
||||
- This should fix the `"$'\r': command not found"` error
|
||||
- to install run `apt-get install dos2unix`
|
||||
- If your Windows isn't in English the Paths may look different
|
||||
Example in other languages
|
||||
- English `/mnt/c/Users/<your-username>/Downloads/Prusa-Firmware-MK3` will be on a German Windows`/mnt/c/Anwender/<your-username>/Downloads/Prusa-Firmware-MK3`
|
||||
#### Compile Prusa-firmware with Ubuntu/Debian Linux subsystem installed
|
||||
- open Ubuntu bash
|
||||
- open Ubuntu bash shell
|
||||
- change to your source code folder (case sensitive)
|
||||
- run `./PF-build.sh`
|
||||
- follow the instructions
|
||||
@ -211,14 +211,14 @@ Q:I built firmware using Arduino and I see "?" instead of numbers in printer use
|
||||
|
||||
A:Step 1.c was omitted or you updated Arduino and now platform.txt located somewhere in your user profile is used.
|
||||
|
||||
Q:I built firmware using Arduino and printer now speaks Klingon (nonsense characters and symbols are displayed @^#$&*°;~ÿ)
|
||||
Q:I built firmware using Arduino and my printer now speaks "Klingon" (nonsense characters and symbols are displayed @^#$&*°;~ÿ)
|
||||
|
||||
A:Step 2.c was omitted.
|
||||
|
||||
Q:What environment does Prusa use to build the firmware in the first place?
|
||||
Q:What environment does Prusa use to build its official firmware releases?
|
||||
|
||||
A:Our production builds are 99.9% equivalent to https://github.com/prusa3d/Prusa-Firmware#linux this is also easiest way to build as only one step is needed - run single script, which downloads patched Arduino from github, builds using it, then extracts translated strings and creates language variants (for MK2x) or language hex file for external SPI flash (MK3x). But you need Linux or Linux in virtual machine. This is also what happens when you open pull request to our repository - all variants are built by Travis http://travis-ci.org/ (to check for compilation errors). You can see, what is happening in .travis.yml. It would be also possible to get hex built by travis, only deploy step is missing in .travis.yml. You can get inspiration how to deploy hex by travis and how to setup travis in https://github.com/prusa3d/MM-control-01/ repository. Final hex is located in ./lang/firmware.hex Community reproduced this for Windows in https://github.com/prusa3d/Prusa-Firmware#using-linux-subsystem-under-windows-10-64-bit or https://github.com/prusa3d/Prusa-Firmware#using-git-bash-under-windows-10-64-bit .
|
||||
A:Our production builds are 99.9% equivalent to https://github.com/prusa3d/Prusa-Firmware#linux this is also easiest way to build as only one step is needed - run a single script, which downloads patched Arduino from GitHub, builds using it, then extracts translated strings and creates language variants (for MK2x) or language hex file for external SPI flash (MK3x). But you need Linux or Linux in a virtual machine. This is also what happens when you open a pull request to our repository - all variants are built by Travis http://travis-ci.org/ (to check for compilation errors). You can see, what is happening in .travis.yml. It would be also possible to get hex built by Travis, only the deploy step is missing in .travis.yml. You can find inspiration on how to deploy hex in Travis and how to setup Travis in https://github.com/prusa3d/MM-control-01/ repository. The final hex is located in ./lang/firmware.hex - community reproduced this for Windows in https://github.com/prusa3d/Prusa-Firmware#using-linux-subsystem-under-windows-10-64-bit or https://github.com/prusa3d/Prusa-Firmware#using-git-bash-under-windows-10-64-bit .
|
||||
|
||||
Q:Why are build instructions for Arduino mess.
|
||||
Q:Why are build instructions for Arduino a mess?
|
||||
|
||||
Y:We are too lazy to ship proper board definition for Arduino. We plan to switch to cmake + ninja to be inherently multiplatform, easily integrate build tools, suport more IDEs, get 10 times shorter build times and be able to update compiler whenever we want.
|
||||
Y:We are too lazy to ship a proper board definition for Arduino. We plan to switch to CMake + ninja to be inherently multiplatform, easily integrate build tools, suport more IDEs, get 10 times shorter build times and be able to update compiler whenever we want.
|
||||
|
30
lang/Community_made_translations.md
Normal file
30
lang/Community_made_translations.md
Normal file
@ -0,0 +1,30 @@
|
||||
## List of Community made translations
|
||||
|
||||
- **Dutch / Nederlands**
|
||||
- Maintainers: **@3d-gussner** and **@vintagepc**
|
||||
- Co-maintainers:
|
||||
- Contributors: **@stelgenhof**
|
||||
- [X] **Active** since March 2021
|
||||
- [X] **Maintained** since September 2019
|
||||
|
||||
- **Romanian / Română**
|
||||
- Maintainers: **@leptun** and **@Hauzman**
|
||||
- Co-maintainers: **@QuantumRoboticsFTC**
|
||||
- Contributors:
|
||||
- [X] **Active** since January 2022
|
||||
- [X] **Maintained** since January 2022
|
||||
|
||||
- **Hungarian / Magyar**
|
||||
- Maintainers: **@AttilaSVK**
|
||||
- Co-maintainers:
|
||||
- Contributors:
|
||||
- [X] **Active** since January 2022
|
||||
- [X] **Maintained** since January 2022
|
||||
|
||||
- **Swedish / Svenska**
|
||||
- Maintainers: **@Painkiller56**
|
||||
- Co-maintainers:
|
||||
- Contributors:
|
||||
- [X] **Active** since January 2022
|
||||
- [X] **Maintained** since January 2022
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
54
tools/README.md
Normal file
54
tools/README.md
Normal file
@ -0,0 +1,54 @@
|
||||
# Host debugging tools for Prusa MK3 firmware
|
||||
|
||||
## Tools
|
||||
|
||||
### ``dump_eeprom``
|
||||
|
||||
Dump the content of the entire EEPROM using the D3 command.
|
||||
Requires ``printcore`` from [Pronterface].
|
||||
|
||||
### ``dump_sram``
|
||||
|
||||
Dump the content of the entire SRAM using the D2 command.
|
||||
Requires ``printcore`` from [Pronterface].
|
||||
|
||||
### ``dump_crash``
|
||||
|
||||
Dump the content of the last crash dump on MK3+ printers using D21.
|
||||
Requires ``printcore`` from [Pronterface].
|
||||
|
||||
### ``elf_mem_map``
|
||||
|
||||
Generate a symbol table map with decoded information starting directly from an ELF firmware with DWARF debugging information (which is the default using the stock board definition).
|
||||
|
||||
When used along with a memory dump obtained from the D2 g-code, show the value of each symbol which is within the address range of the dump.
|
||||
|
||||
When used with ``--map`` and a single elf file, generate a map consisting of memory location and source location for each statically-addressed variable.
|
||||
|
||||
With ``--qdirstat`` and a single elf file, generate a [qdirstat](https://github.com/shundhammer/qdirstat) compatible cache file which can be loaded to inspect memory utilization interactively in a treemap.
|
||||
|
||||
This assumes the running firmware generating the dump and the elf file are the same.
|
||||
Requires Python3 and the [pyelftools](https://github.com/eliben/pyelftools) module.
|
||||
|
||||
### ``dump2bin``
|
||||
|
||||
Parse and decode a memory dump obtained from the D2/D21/D23 g-code into readable metadata and binary. The output binary is padded and extended to fit the original address range.
|
||||
|
||||
### ``xfimg2dump``
|
||||
|
||||
Extract a crash dump from an external flash image and output the same format produced by the D21 g-code.
|
||||
|
||||
### ``update_eeprom``
|
||||
|
||||
Given one EEPROM dump, convert the dump to update instructions that can be sent to a printer.
|
||||
|
||||
Given two EEPROM dumps, produces only the required instructions needed to update the contents from the first to the second. This is currently quite crude and assumes dumps are aligned (starting from the same address or same stride).
|
||||
|
||||
Optionally writes the instructions to the specified port (requires ``printcore`` from [Pronterface]).
|
||||
|
||||
### ``noreset``
|
||||
|
||||
Set the required TTY flags on the specified port to avoid reset-on-connect for *subsequent* requests (issuing this command might still cause the printer to reset).
|
||||
|
||||
|
||||
[Pronterface]: https://github.com/kliment/Printrun
|
59
tools/dump2bin
Executable file
59
tools/dump2bin
Executable file
@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import os, sys
|
||||
|
||||
from lib.dump import decode_dump
|
||||
|
||||
|
||||
def main():
|
||||
# parse the arguments
|
||||
ap = argparse.ArgumentParser(description="""
|
||||
Parse and decode a memory dump obtained from the D2/D21/D23 g-code
|
||||
into readable metadata and binary. The output binary is padded and
|
||||
extended to fit the original address range.
|
||||
""")
|
||||
ap.add_argument('-i', dest='info', action='store_true',
|
||||
help='display crash info only')
|
||||
ap.add_argument('dump')
|
||||
ap.add_argument('output', nargs='?')
|
||||
args = ap.parse_args()
|
||||
|
||||
# decode the dump data
|
||||
dump = decode_dump(args.dump)
|
||||
if dump is None:
|
||||
return os.EX_DATAERR
|
||||
|
||||
# output descriptors
|
||||
if args.info:
|
||||
o_fd = None
|
||||
o_md = sys.stdout
|
||||
elif args.output is None:
|
||||
o_fd = sys.stdout.buffer
|
||||
o_md = sys.stderr
|
||||
else:
|
||||
o_fd = open(args.output, 'wb')
|
||||
o_md = sys.stdout
|
||||
|
||||
# output binary
|
||||
if o_fd:
|
||||
o_fd.write(dump.data)
|
||||
o_fd.close()
|
||||
|
||||
# metadata
|
||||
print(' dump type: {typ}\n'
|
||||
'crash reason: {reason}\n'
|
||||
' registers: {regs}\n'
|
||||
' PC: {pc}\n'
|
||||
' SP: {sp}\n'
|
||||
' ranges: {ranges}'.format(
|
||||
typ=dump.typ,
|
||||
reason=dump.reason.name if dump.reason is not None else 'N/A',
|
||||
regs=dump.regs,
|
||||
pc='{:#x}'.format(dump.pc) if dump.pc is not None else 'N/A',
|
||||
sp='{:#x}'.format(dump.sp) if dump.sp is not None else 'N/A',
|
||||
ranges=str(dump.ranges)),
|
||||
file=o_md)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
exit(main())
|
17
tools/dump_crash
Executable file
17
tools/dump_crash
Executable file
@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
prg=$(basename "$0")
|
||||
port="$1"
|
||||
if [ -z "$port" -o "$port" = "-h" ]
|
||||
then
|
||||
echo "usage: $0 <port>" >&2
|
||||
echo "Connect to <port> and dump the content of last crash using D21 to stdout" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -e
|
||||
tmp=$(mktemp)
|
||||
trap "rm -f \"$tmp\"" EXIT
|
||||
|
||||
echo D21 > "$tmp"
|
||||
printcore -v "$port" "$tmp" 2>&1 | \
|
||||
sed -ne '/^RECV: D21 /,/RECV: ok$/s/^RECV: //p'
|
17
tools/dump_eeprom
Executable file
17
tools/dump_eeprom
Executable file
@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
prg=$(basename "$0")
|
||||
port="$1"
|
||||
if [ -z "$port" -o "$port" = "-h" ]
|
||||
then
|
||||
echo "usage: $0 <port>" >&2
|
||||
echo "Connect to <port> and dump the content of the EEPROM using D3 to stdout" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -e
|
||||
tmp=$(mktemp)
|
||||
trap "rm -f \"$tmp\"" EXIT
|
||||
|
||||
echo D3 > "$tmp"
|
||||
printcore -v "$port" "$tmp" 2>&1 | \
|
||||
sed -ne '/^RECV: D3 /,/RECV: ok$/s/^RECV: //p'
|
17
tools/dump_sram
Executable file
17
tools/dump_sram
Executable file
@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
prg=$(basename "$0")
|
||||
port="$1"
|
||||
if [ -z "$port" -o "$port" = "-h" ]
|
||||
then
|
||||
echo "usage: $0 <port>" >&2
|
||||
echo "Connect to <port> and dump the content of the SRAM using D2 to stdout" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -e
|
||||
tmp=$(mktemp)
|
||||
trap "rm -f \"$tmp\"" EXIT
|
||||
|
||||
echo D2 > "$tmp"
|
||||
printcore -v "$port" "$tmp" 2>&1 | \
|
||||
sed -ne '/^RECV: D2 /,/RECV: ok$/s/^RECV: //p'
|
389
tools/elf_mem_map
Executable file
389
tools/elf_mem_map
Executable file
@ -0,0 +1,389 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import elftools.elf.elffile
|
||||
import elftools.dwarf.descriptions
|
||||
from collections import namedtuple
|
||||
from struct import unpack
|
||||
import os
|
||||
|
||||
from lib.dump import decode_dump
|
||||
from lib.avr import *
|
||||
|
||||
|
||||
Entry = namedtuple('Entry', ['name', 'loc', 'size', 'declpos'])
|
||||
Member = namedtuple('Member', ['name', 'off', 'size'])
|
||||
|
||||
|
||||
def array_inc(loc, dim, idx=0):
|
||||
if idx == len(dim):
|
||||
return True
|
||||
loc[idx] += 1
|
||||
if loc[idx] == dim[idx]:
|
||||
loc[idx] = 0
|
||||
return array_inc(loc, dim, idx+1)
|
||||
return False
|
||||
|
||||
def get_type_size(type_DIE):
|
||||
while True:
|
||||
if 'DW_AT_byte_size' in type_DIE.attributes:
|
||||
return type_DIE, type_DIE.attributes.get('DW_AT_byte_size').value
|
||||
if 'DW_AT_type' not in type_DIE.attributes:
|
||||
return None
|
||||
type_DIE = type_DIE.get_DIE_from_attribute('DW_AT_type')
|
||||
|
||||
def get_type_arrsize(type_DIE):
|
||||
size = get_type_size(type_DIE)
|
||||
if size is None:
|
||||
return None
|
||||
byte_size = size[1]
|
||||
if size[0].tag != 'DW_TAG_pointer_type':
|
||||
array_DIE = get_type_def(type_DIE, 'DW_TAG_array_type')
|
||||
if array_DIE is not None:
|
||||
for range_DIE in array_DIE.iter_children():
|
||||
if range_DIE.tag == 'DW_TAG_subrange_type' and \
|
||||
'DW_AT_upper_bound' in range_DIE.attributes:
|
||||
dim = range_DIE.attributes['DW_AT_upper_bound'].value + 1
|
||||
byte_size *= dim
|
||||
return byte_size
|
||||
|
||||
def get_type_def(type_DIE, type_tag):
|
||||
while True:
|
||||
if type_DIE.tag == type_tag:
|
||||
return type_DIE
|
||||
if 'DW_AT_type' not in type_DIE.attributes:
|
||||
return None
|
||||
type_DIE = type_DIE.get_DIE_from_attribute('DW_AT_type')
|
||||
|
||||
def get_FORM_block1(attr):
|
||||
if attr.form != 'DW_FORM_block1':
|
||||
return None
|
||||
if attr.value[0] == 3: # OP_addr
|
||||
return int.from_bytes(attr.value[1:], 'little')
|
||||
if attr.value[0] == 35: # OP_plus_uconst (ULEB128)
|
||||
v = 0
|
||||
s = 0
|
||||
for b in attr.value[1:]:
|
||||
v |= (b & 0x7f) << s
|
||||
if b & 0x80 == 0:
|
||||
break
|
||||
s += 7
|
||||
return v
|
||||
return None
|
||||
|
||||
|
||||
def get_array_dims(DIE):
|
||||
array_DIE = get_type_def(DIE, 'DW_TAG_array_type')
|
||||
if array_DIE is None:
|
||||
return []
|
||||
|
||||
array_dim = []
|
||||
for range_DIE in array_DIE.iter_children():
|
||||
if range_DIE.tag == 'DW_TAG_subrange_type' and \
|
||||
'DW_AT_upper_bound' in range_DIE.attributes:
|
||||
array_dim.append(range_DIE.attributes['DW_AT_upper_bound'].value + 1)
|
||||
return array_dim
|
||||
|
||||
|
||||
def get_struct_members(DIE, entry, expand_structs, struct_gaps):
|
||||
struct_DIE = get_type_def(DIE, 'DW_TAG_structure_type')
|
||||
if struct_DIE is None:
|
||||
return []
|
||||
|
||||
members = []
|
||||
for member_DIE in struct_DIE.iter_children():
|
||||
if member_DIE.tag == 'DW_TAG_member' and 'DW_AT_name' in member_DIE.attributes:
|
||||
m_name = member_DIE.attributes['DW_AT_name'].value.decode('ascii')
|
||||
m_off = get_FORM_block1(member_DIE.attributes['DW_AT_data_member_location'])
|
||||
m_byte_size = get_type_size(member_DIE)[1]
|
||||
|
||||
# still expand member arrays
|
||||
m_array_dim = get_array_dims(member_DIE)
|
||||
|
||||
if m_byte_size == 1 and len(m_array_dim) > 1:
|
||||
# likely string, remove one dimension
|
||||
m_byte_size *= m_array_dim.pop()
|
||||
if len(m_array_dim) == 0 or (len(m_array_dim) == 1 and m_array_dim[0] == 1):
|
||||
# plain entry
|
||||
members.append(Member(m_name, m_off, m_byte_size))
|
||||
elif len(m_array_dim) == 1 and m_byte_size == 1:
|
||||
# likely string, avoid expansion
|
||||
members.append(Member(m_name + '[]', m_off, m_array_dim[0]))
|
||||
else:
|
||||
# expand array entries
|
||||
m_array_pos = m_off
|
||||
m_array_loc = [0] * len(m_array_dim)
|
||||
while True:
|
||||
# location index
|
||||
sfx = ''
|
||||
for d in range(len(m_array_dim)):
|
||||
sfx += '[{}]'.format(str(m_array_loc[d]).rjust(len(str(m_array_dim[d]-1)), '0'))
|
||||
members.append(Member(m_name + sfx, m_array_pos, m_byte_size))
|
||||
# advance
|
||||
if array_inc(m_array_loc, m_array_dim):
|
||||
break
|
||||
m_array_pos += m_byte_size
|
||||
|
||||
if struct_gaps and len(members):
|
||||
# fill gaps in the middle
|
||||
members = list(sorted(members, key=lambda x: x.off))
|
||||
last_end = 0
|
||||
for n in range(len(members)):
|
||||
member = members[n]
|
||||
if member.off > last_end:
|
||||
members.append(Member('*UNKNOWN*', last_end, member.off - last_end))
|
||||
last_end = member.off + member.size
|
||||
|
||||
if struct_gaps and len(members):
|
||||
# fill gap at the end
|
||||
members = list(sorted(members, key=lambda x: x.off))
|
||||
last = members[-1]
|
||||
last_end = last.off + last.size
|
||||
if entry.size > last_end:
|
||||
members.append(Member('*UNKNOWN*', last_end, entry.size - last_end))
|
||||
|
||||
return members
|
||||
|
||||
|
||||
def get_elf_globals(path, expand_structs, struct_gaps=True):
|
||||
fd = open(path, "rb")
|
||||
if fd is None:
|
||||
return
|
||||
elffile = elftools.elf.elffile.ELFFile(fd)
|
||||
if elffile is None or not elffile.has_dwarf_info():
|
||||
return
|
||||
|
||||
# probably not needed, since we're decoding expressions manually
|
||||
elftools.dwarf.descriptions.set_global_machine_arch(elffile.get_machine_arch())
|
||||
dwarfinfo = elffile.get_dwarf_info()
|
||||
|
||||
grefs = []
|
||||
for CU in dwarfinfo.iter_CUs():
|
||||
file_entries = dwarfinfo.line_program_for_CU(CU).header["file_entry"]
|
||||
|
||||
for DIE in CU.iter_DIEs():
|
||||
# handle only variable types
|
||||
if DIE.tag != 'DW_TAG_variable':
|
||||
continue
|
||||
if 'DW_AT_location' not in DIE.attributes:
|
||||
continue
|
||||
if 'DW_AT_name' not in DIE.attributes and \
|
||||
'DW_AT_abstract_origin' not in DIE.attributes:
|
||||
continue
|
||||
|
||||
# handle locations encoded directly as DW_OP_addr (leaf globals)
|
||||
loc = get_FORM_block1(DIE.attributes['DW_AT_location'])
|
||||
if loc is None or loc < SRAM_OFFSET or loc >= EEPROM_OFFSET:
|
||||
continue
|
||||
loc -= SRAM_OFFSET
|
||||
|
||||
# variable name/type
|
||||
if 'DW_AT_name' not in DIE.attributes and \
|
||||
'DW_AT_abstract_origin' in DIE.attributes:
|
||||
DIE = DIE.get_DIE_from_attribute('DW_AT_abstract_origin')
|
||||
if 'DW_AT_location' in DIE.attributes:
|
||||
# duplicate reference (handled directly), skip
|
||||
continue
|
||||
if 'DW_AT_name' not in DIE.attributes:
|
||||
continue
|
||||
if 'DW_AT_type' not in DIE.attributes:
|
||||
continue
|
||||
|
||||
name = DIE.attributes['DW_AT_name'].value.decode('ascii')
|
||||
|
||||
# get final storage size
|
||||
size = get_type_size(DIE)
|
||||
if size is None:
|
||||
continue
|
||||
byte_size = size[1]
|
||||
|
||||
# location of main definition
|
||||
declpos = ''
|
||||
if 'DW_AT_decl_file' in DIE.attributes and \
|
||||
'DW_AT_decl_line' in DIE.attributes:
|
||||
line = DIE.attributes['DW_AT_decl_line'].value
|
||||
fname = DIE.attributes['DW_AT_decl_file'].value
|
||||
if fname and fname - 1 < len(file_entries):
|
||||
fname = file_entries[fname-1].name.decode('ascii')
|
||||
declpos = '{}:{}'.format(fname, line)
|
||||
|
||||
# fetch array dimensions (if known)
|
||||
array_dim = get_array_dims(DIE)
|
||||
|
||||
# fetch structure members (one level only)
|
||||
entry = Entry(name, loc, byte_size, declpos)
|
||||
if not expand_structs or size[0].tag == 'DW_TAG_pointer_type':
|
||||
members = []
|
||||
else:
|
||||
members = get_struct_members(DIE, entry, expand_structs, struct_gaps)
|
||||
|
||||
def expand_members(entry, members):
|
||||
if len(members) == 0:
|
||||
grefs.append(entry)
|
||||
else:
|
||||
for member in members:
|
||||
grefs.append(Entry(entry.name + '.' + member.name,
|
||||
entry.loc + member.off, member.size,
|
||||
entry.declpos))
|
||||
|
||||
if byte_size == 1 and len(array_dim) > 1:
|
||||
# likely string, remove one dimension
|
||||
byte_size *= array_dim.pop()
|
||||
if len(array_dim) == 0 or (len(array_dim) == 1 and array_dim[0] == 1):
|
||||
# plain entry
|
||||
expand_members(entry, members)
|
||||
elif len(array_dim) == 1 and byte_size == 1:
|
||||
# likely string, avoid expansion
|
||||
grefs.append(Entry(entry.name + '[]', entry.loc,
|
||||
array_dim[0], entry.declpos))
|
||||
else:
|
||||
# expand array entries
|
||||
array_pos = loc
|
||||
array_loc = [0] * len(array_dim)
|
||||
while True:
|
||||
# location index
|
||||
sfx = ''
|
||||
for d in range(len(array_dim)):
|
||||
sfx += '[{}]'.format(str(array_loc[d]).rjust(len(str(array_dim[d]-1)), '0'))
|
||||
expand_members(Entry(entry.name + sfx, array_pos,
|
||||
byte_size, entry.declpos), members)
|
||||
# advance
|
||||
if array_inc(array_loc, array_dim):
|
||||
break
|
||||
array_pos += byte_size
|
||||
|
||||
return grefs
|
||||
|
||||
|
||||
def annotate_refs(grefs, addr, data, width, gaps=True, overlaps=True):
|
||||
last_end = None
|
||||
for entry in grefs:
|
||||
if entry.loc < addr:
|
||||
continue
|
||||
if entry.loc + entry.size > addr + len(data):
|
||||
continue
|
||||
|
||||
pos = entry.loc-addr
|
||||
end_pos = pos + entry.size
|
||||
buf = data[pos:end_pos]
|
||||
|
||||
buf_repr = ''
|
||||
if len(buf) in [1, 2, 4]:
|
||||
# attempt to decode as integers
|
||||
buf_repr += ' I:' + str(int.from_bytes(buf, 'little')).rjust(10)
|
||||
if len(buf) in [4, 8]:
|
||||
# attempt to decode as floats
|
||||
typ = 'f' if len(buf) == 4 else 'd'
|
||||
buf_repr += ' F:' + '{:10.3f}'.format(unpack(typ, buf)[0])
|
||||
|
||||
if last_end is not None:
|
||||
if gaps and last_end < pos:
|
||||
# decode gaps
|
||||
gap_size = pos - last_end
|
||||
gap_buf = data[last_end:pos]
|
||||
print('{:04x} {} {:4} R:{}'.format(addr+last_end, "*UNKNOWN*".ljust(width),
|
||||
gap_size, gap_buf.hex()))
|
||||
if overlaps and last_end > pos + 1:
|
||||
gap_size = pos - last_end
|
||||
print('{:04x} {} {:4}'.format(addr+last_end, "*OVERLAP*".ljust(width), gap_size))
|
||||
|
||||
print('{:04x} {} {:4}{} R:{}'.format(entry.loc, entry.name.ljust(width),
|
||||
entry.size, buf_repr, buf.hex()))
|
||||
last_end = end_pos
|
||||
|
||||
|
||||
def print_map(grefs):
|
||||
print('OFFSET\tSIZE\tNAME\tDECLPOS')
|
||||
for entry in grefs:
|
||||
print('{:x}\t{}\t{}\t{}'.format(entry.loc, entry.size, entry.name, entry.declpos))
|
||||
|
||||
|
||||
def print_qdirstat(grefs):
|
||||
print('[qdirstat 1.0 cache file]')
|
||||
|
||||
entries = {}
|
||||
for entry in grefs:
|
||||
# do not output registers when looking at space usage
|
||||
if entry.loc < SRAM_START:
|
||||
continue
|
||||
|
||||
paths = list(filter(None, re.split(r'[\[\].]', entry.name)))
|
||||
base = entries
|
||||
for i in range(len(paths) - 1):
|
||||
name = paths[i]
|
||||
if name not in base:
|
||||
base[name] = {}
|
||||
base = base[name]
|
||||
name = paths[-1]
|
||||
if name in base:
|
||||
name = '{}_{:x}'.format(entry.name, entry.loc)
|
||||
base[name] = entry.size
|
||||
|
||||
def walker(root, prefix):
|
||||
files = []
|
||||
dirs = []
|
||||
|
||||
for name, entries in root.items():
|
||||
if type(entries) == int:
|
||||
files.append([name, entries])
|
||||
else:
|
||||
dirs.append([name, entries])
|
||||
|
||||
# print files
|
||||
print('D\t{}\t{}\t0x0'.format(prefix, 0))
|
||||
for name, size in files:
|
||||
print('F\t{}\t{}\t0x0'.format(name, size))
|
||||
|
||||
# recurse directories
|
||||
for name, entries in dirs:
|
||||
walker(entries, prefix + '/' + name)
|
||||
|
||||
walker(entries, '/')
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description="""
|
||||
Generate a symbol table map starting directly from an ELF
|
||||
firmware with DWARF3 debugging information.
|
||||
When used along with a memory dump obtained from the D2/D21/D23 g-code,
|
||||
show the value of each symbol which is within the address range.
|
||||
""")
|
||||
ap.add_argument('elf', help='ELF file containing DWARF debugging information')
|
||||
ap.add_argument('--no-gaps', action='store_true',
|
||||
help='do not dump memory inbetween known symbols')
|
||||
ap.add_argument('--no-expand-structs', action='store_true',
|
||||
help='do not decode structure data')
|
||||
ap.add_argument('--overlaps', action='store_true',
|
||||
help='annotate overlaps greater than 1 byte')
|
||||
ap.add_argument('--name-width', type=int, default=50,
|
||||
help='set name column width')
|
||||
g = ap.add_mutually_exclusive_group(required=True)
|
||||
g.add_argument('dump', nargs='?', help='RAM dump obtained from D2 g-code')
|
||||
g.add_argument('--map', action='store_true', help='dump global memory map')
|
||||
g.add_argument('--qdirstat', action='store_true',
|
||||
help='dump qdirstat-compatible size usage map')
|
||||
args = ap.parse_args()
|
||||
|
||||
grefs = get_elf_globals(args.elf, expand_structs=not args.no_expand_structs)
|
||||
grefs = list(sorted(grefs, key=lambda x: x.loc))
|
||||
if args.map:
|
||||
print_map(grefs)
|
||||
elif args.qdirstat:
|
||||
print_qdirstat(grefs)
|
||||
else:
|
||||
# fetch the memory data
|
||||
dump = decode_dump(args.dump)
|
||||
if dump is None:
|
||||
return os.EX_DATAERR
|
||||
|
||||
# strip padding, if present
|
||||
addr_start = dump.ranges[0][0]
|
||||
addr_end = dump.ranges[-1][0]+dump.ranges[-1][1]
|
||||
data = dump.data[addr_start:addr_end]
|
||||
|
||||
annotate_refs(grefs, addr_start, data,
|
||||
width=args.name_width,
|
||||
gaps=not args.no_gaps,
|
||||
overlaps=args.overlaps)
|
||||
|
||||
if __name__ == '__main__':
|
||||
exit(main())
|
4
tools/lib/avr.py
Normal file
4
tools/lib/avr.py
Normal file
@ -0,0 +1,4 @@
|
||||
SRAM_START = 0x200
|
||||
SRAM_SIZE = 0x2000
|
||||
SRAM_OFFSET = 0x800000
|
||||
EEPROM_OFFSET = 0x810000
|
169
tools/lib/dump.py
Normal file
169
tools/lib/dump.py
Normal file
@ -0,0 +1,169 @@
|
||||
import sys
|
||||
import re
|
||||
import enum
|
||||
import struct
|
||||
from . import avr
|
||||
|
||||
|
||||
FILL_BYTE = b'\0' # used to fill memory gaps in the dump
|
||||
DUMP_MAGIC = 0x55525547 # XFLASH dump magic
|
||||
DUMP_OFFSET = 0x3d000 # XFLASH dump offset
|
||||
DUMP_SIZE = 0x2300 # XFLASH dump size
|
||||
|
||||
class CrashReason(enum.IntEnum):
|
||||
MANUAL = 0
|
||||
STACK_ERROR = 1
|
||||
WATCHDOG = 2
|
||||
BAD_ISR = 3
|
||||
|
||||
class Dump():
|
||||
def __init__(self, typ, reason, regs, pc, sp, data, ranges):
|
||||
self.typ = typ
|
||||
self.reason = reason
|
||||
self.regs = regs
|
||||
self.pc = pc
|
||||
self.sp = sp
|
||||
self.data = data
|
||||
self.ranges = ranges
|
||||
|
||||
|
||||
# expand the buffer identified by addr+data to fill the region start+size
|
||||
def region_expand(addr, data, start, size):
|
||||
if start < addr:
|
||||
data = FILL_BYTE * (addr - start) + data
|
||||
addr = start
|
||||
end = start + size
|
||||
data_end = addr + len(data)
|
||||
if end > data_end:
|
||||
data += FILL_BYTE * (data_end - end)
|
||||
return addr, data
|
||||
|
||||
|
||||
def merge_ranges(ranges):
|
||||
ranges = list(sorted(ranges, key=lambda x: x[0]))
|
||||
if len(ranges) < 2:
|
||||
return ranges
|
||||
|
||||
ret = [ranges[0]]
|
||||
for cur in ranges[1:]:
|
||||
last = ret[-1]
|
||||
last_end = last[0] + last[1]
|
||||
if last_end < cur[0]:
|
||||
ret.append(cur)
|
||||
else:
|
||||
cur_end = cur[0] + cur[1]
|
||||
last = (last[0], max(last_end, cur_end) - last[0])
|
||||
ret[-1] = last
|
||||
return ret
|
||||
|
||||
|
||||
def decode_dump(path):
|
||||
fd = open(path, 'r')
|
||||
if fd is None:
|
||||
return None
|
||||
|
||||
buf_addr = None # starting address
|
||||
buf_data = None # data
|
||||
|
||||
typ = None # dump type
|
||||
reason = None # crash reason
|
||||
regs = None # registers present
|
||||
pc = None # PC address
|
||||
sp = None # SP address
|
||||
ranges = [] # dumped ranges
|
||||
|
||||
in_dump = False
|
||||
for line in enumerate(fd):
|
||||
line = (line[0], line[1].rstrip())
|
||||
tokens = line[1].split(maxsplit=1)
|
||||
|
||||
def line_error():
|
||||
print('malformed line {}: {}'.format(*line), file=sys.stderr)
|
||||
|
||||
# handle metadata
|
||||
if not in_dump:
|
||||
if len(tokens) > 0 and tokens[0] in ['D2', 'D21', 'D23']:
|
||||
in_dump = True
|
||||
typ = tokens[0]
|
||||
continue
|
||||
else:
|
||||
if len(tokens) == 0:
|
||||
line_error()
|
||||
continue
|
||||
elif tokens[0] == 'ok':
|
||||
break
|
||||
elif tokens[0] == 'error:' and len(tokens) == 2:
|
||||
values = tokens[1].split(' ')
|
||||
if typ == 'D23' and len(values) >= 3:
|
||||
reason = CrashReason(int(values[0], 0))
|
||||
pc = int(values[1], 0)
|
||||
sp = int(values[2], 0)
|
||||
else:
|
||||
line_error()
|
||||
continue
|
||||
elif len(tokens) != 2 or not re.match(r'^[0-9a-fA-F]+$', tokens[0]):
|
||||
line_error()
|
||||
continue
|
||||
|
||||
# decode hex data
|
||||
addr = int.from_bytes(bytes.fromhex(tokens[0]), 'big')
|
||||
data = bytes.fromhex(tokens[1])
|
||||
ranges.append((addr, len(data)))
|
||||
|
||||
if buf_addr is None:
|
||||
buf_addr = addr
|
||||
buf_data = data
|
||||
else:
|
||||
# grow buffer as needed
|
||||
buf_addr, buf_data = region_expand(buf_addr, buf_data,
|
||||
addr, len(data))
|
||||
|
||||
# replace new part
|
||||
rep_start = addr - buf_addr
|
||||
rep_end = rep_start + len(data)
|
||||
buf_data = buf_data[:rep_start] + data + buf_data[rep_end:]
|
||||
|
||||
# merge continuous ranges
|
||||
ranges = merge_ranges(ranges)
|
||||
|
||||
if typ == 'D2':
|
||||
# D2 doesn't guarantee registers to be present
|
||||
regs = len(ranges) > 0 and \
|
||||
ranges[0][0] == 0 and \
|
||||
ranges[0][1] >= avr.SRAM_START
|
||||
|
||||
# fill to fit for easy loading
|
||||
buf_addr, buf_data = region_expand(
|
||||
buf_addr, buf_data, 0, avr.SRAM_START + avr.SRAM_SIZE)
|
||||
|
||||
elif typ == 'D23':
|
||||
# check if the dump is complete
|
||||
if len(ranges) != 1 or ranges[0][0] != 0 or \
|
||||
ranges[0][1] != avr.SRAM_START + avr.SRAM_SIZE:
|
||||
print('error: incomplete D23 dump', file=sys.stderr)
|
||||
return None
|
||||
|
||||
regs = True
|
||||
if reason is None:
|
||||
print('warning: no error line in D23', file=sys.stderr)
|
||||
|
||||
elif typ == 'D21':
|
||||
if len(ranges) != 1 or len(buf_data) != (avr.SRAM_START + avr.SRAM_SIZE + 256):
|
||||
print('error: incomplete D21 dump', file=sys.stderr)
|
||||
return None
|
||||
|
||||
# decode the header structure
|
||||
magic, regs_present, crash_reason, pc, sp = struct.unpack('<LBBLH', buf_data[0:12])
|
||||
if magic != DUMP_MAGIC:
|
||||
print('error: invalid dump header in D21', file=sys.stderr)
|
||||
return None
|
||||
|
||||
regs = bool(regs_present)
|
||||
reason = CrashReason(crash_reason)
|
||||
|
||||
# extract the data section
|
||||
buf_addr = 0
|
||||
buf_data = buf_data[256:]
|
||||
ranges[0] = (0, len(buf_data))
|
||||
|
||||
return Dump(typ, reason, regs, pc, sp, buf_data, ranges)
|
12
tools/noreset
Executable file
12
tools/noreset
Executable file
@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
prg=$(basename "$0")
|
||||
port="$1"
|
||||
if [ -z "$port" -o "$port" = "-h" ]
|
||||
then
|
||||
echo "usage: $0 <port>" >&2
|
||||
echo "Set TTY flags on <port> to avoid reset-on-connect" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -e
|
||||
stty -F "$port" -hup
|
54
tools/update_eeprom
Executable file
54
tools/update_eeprom
Executable file
@ -0,0 +1,54 @@
|
||||
#!/bin/sh
|
||||
prg=$(basename "$0")
|
||||
|
||||
# parse arguments
|
||||
while getopts f:h optname
|
||||
do
|
||||
case $optname in
|
||||
f) port="$OPTARG" ;;
|
||||
*) help=1 ;;
|
||||
esac
|
||||
done
|
||||
shift `expr $OPTIND - 1`
|
||||
|
||||
old="$1"
|
||||
new="$2"
|
||||
|
||||
if [ -z "$old" -o "$help" = "-h" -o "$#" -gt 2 ]
|
||||
then
|
||||
echo "usage: $0 [-f <port>] <old dump> [<new dump>]" >&2
|
||||
echo "Convert <old dump> to instructions to update instructions." >&2
|
||||
echo "With <new dump>, generate instructions to update EEPROM changes only." >&2
|
||||
echo "Optionally write such changes directly if <port> if given." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -e
|
||||
instr=$(mktemp)
|
||||
trap "rm -f \"$instr\"" EXIT
|
||||
|
||||
convert()
|
||||
{
|
||||
sed -ne 's/^\([0-9a-f]\{4\}\) \([0-9a-f ]*\)$/D3 Ax\1 C16 X\2/p' "$@"
|
||||
}
|
||||
|
||||
if [ -z "$new" ]; then
|
||||
# convert the instructions to updates
|
||||
convert "$old" > "$instr"
|
||||
else
|
||||
tmp1=$(mktemp)
|
||||
tmp2=$(mktemp)
|
||||
trap "rm -f \"$tmp1\" \"$tmp2\"" EXIT
|
||||
|
||||
convert "$old" > "$tmp1"
|
||||
convert "$new" > "$tmp2"
|
||||
|
||||
comm -13 "$tmp1" "$tmp2" > "$instr"
|
||||
fi
|
||||
|
||||
# write the instructions if requested
|
||||
if [ -z "$port" ]; then
|
||||
cat "$instr"
|
||||
else
|
||||
printcore -v "$port" "$instr"
|
||||
fi
|
89
tools/utils.gdb
Normal file
89
tools/utils.gdb
Normal file
@ -0,0 +1,89 @@
|
||||
# -*- gdb-script -*-
|
||||
|
||||
define load_dump
|
||||
restore $arg0 binary 0x800000
|
||||
set $pc = (((unsigned long)$arg1) - 2) << 1
|
||||
set $sp = $arg2
|
||||
where
|
||||
end
|
||||
|
||||
document load_dump
|
||||
Load a crash dump, setup PC/SP and show the current backtrace
|
||||
Usage: load_dump <file> <PC-addr> <SP-addr>
|
||||
end
|
||||
|
||||
|
||||
define sp_skip
|
||||
if $argc == 0
|
||||
set $shift = 3
|
||||
else
|
||||
set $shift = $arg0
|
||||
end
|
||||
set $new_pc = ((((unsigned long)*(uint8_t*)($sp+$shift+1)) << 16) + \
|
||||
(((unsigned long)*(uint8_t*)($sp+$shift+2)) << 8) + \
|
||||
(((unsigned long)*(uint8_t*)($sp+$shift+3)) << 0)) << 1
|
||||
set $new_sp = $sp+$shift+3
|
||||
select-frame 0
|
||||
set $saved_pc = $pc
|
||||
set $saved_sp = $sp
|
||||
set $pc = $new_pc
|
||||
set $sp = $new_sp
|
||||
where
|
||||
end
|
||||
|
||||
document sp_skip
|
||||
Decode the PC address at SP+offset, then show the resulting stack.
|
||||
The default (and minimum) offset is 3.
|
||||
Usage: sp_skip [off]
|
||||
end
|
||||
|
||||
|
||||
define sp_restore
|
||||
select-frame 0
|
||||
set $pc = $saved_pc
|
||||
set $sp = $saved_sp
|
||||
where
|
||||
end
|
||||
|
||||
document sp_restore
|
||||
Undo an sp_skip move (restore existing PC/SP positions)
|
||||
Usage: sp_restore
|
||||
end
|
||||
|
||||
|
||||
define sp_test
|
||||
sp_skip $arg0
|
||||
set $pc = $saved_pc
|
||||
set $sp = $saved_sp
|
||||
end
|
||||
|
||||
document sp_test
|
||||
Attempt to decode the PC address at SP+offset, then show the resulting stack.
|
||||
The default (and minimum) offset is 3.
|
||||
Usage: sp_test [off]
|
||||
end
|
||||
|
||||
|
||||
define sp_scan
|
||||
dont-repeat
|
||||
|
||||
if $argc == 0
|
||||
set $sp_end = 0x802200
|
||||
else
|
||||
set $sp_end = $arg0
|
||||
end
|
||||
|
||||
set $sp_pos = $sp
|
||||
while $sp_pos < ($sp_end-4)
|
||||
set $sp_off = $sp_pos - $sp
|
||||
printf "**** scanning %#x (+%u) ****\n", $sp_pos, $sp_off
|
||||
sp_test $sp_off
|
||||
set $sp_pos += 1
|
||||
end
|
||||
end
|
||||
|
||||
document sp_scan
|
||||
Attempt to decode PC at any location starting from the SP+3 and up to SP-end
|
||||
(by default the end of the SRAM) and show the resulting stack at all locations.
|
||||
Usage: sp_scan [SP-end]
|
||||
end
|
46
tools/xfimg2dump
Executable file
46
tools/xfimg2dump
Executable file
@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import struct
|
||||
import os, sys
|
||||
|
||||
from lib.dump import DUMP_MAGIC, DUMP_OFFSET, DUMP_SIZE
|
||||
|
||||
|
||||
def error(msg):
|
||||
print(msg, file=sys.stderr)
|
||||
|
||||
def main():
|
||||
# parse the arguments
|
||||
ap = argparse.ArgumentParser(description="""
|
||||
Extract a crash dump from an external flash image and output
|
||||
the same format produced by the D21 g-code.
|
||||
""")
|
||||
ap.add_argument('image')
|
||||
args = ap.parse_args()
|
||||
|
||||
# read the image
|
||||
off = DUMP_OFFSET
|
||||
with open(args.image, 'rb') as fd:
|
||||
fd.seek(off)
|
||||
data = fd.read(DUMP_SIZE)
|
||||
if len(data) != DUMP_SIZE:
|
||||
error('incorrect image size')
|
||||
return os.EX_DATAERR
|
||||
|
||||
# check for magic header
|
||||
magic, = struct.unpack('<L', data[:4])
|
||||
if magic != DUMP_MAGIC:
|
||||
error('invalid dump magic or no dump')
|
||||
return os.EX_DATAERR
|
||||
|
||||
# output D21 dump
|
||||
print('D21 - read crash dump', end='')
|
||||
for i in range(len(data)):
|
||||
if i % 16 == 0:
|
||||
print('\n{:06x} '.format(off + i), end='')
|
||||
print(' {:02x}'.format(data[i]), end='')
|
||||
print('\nok')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
exit(main())
|
Loading…
Reference in New Issue
Block a user