diff options
Diffstat (limited to 'lib/simulator/hibernate.tcl')
-rwxr-xr-x | lib/simulator/hibernate.tcl | 1051 |
1 files changed, 1051 insertions, 0 deletions
diff --git a/lib/simulator/hibernate.tcl b/lib/simulator/hibernate.tcl new file mode 100755 index 0000000..c35f4f8 --- /dev/null +++ b/lib/simulator/hibernate.tcl @@ -0,0 +1,1051 @@ +#!/usr/bin/tclsh +# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net ) + +############################################################################ +# Copyright (C) 2007-2009 by Martin Ošmera # +# martin.osmera@gmail.com # +# # +# This program is free software; you can redistribute it and#or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation; either version 2 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program; if not, write to the # +# Free Software Foundation, Inc., # +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # +############################################################################ + +# -------------------------------------------------------------------------- +# DESCRIPTION +# Provides program hibernation capability. It ohter words it can save +# current state of simulator engine to a file (*.m5ihib) and later +# restrore state save in that file and resume hibernated program. +# +# Usage: +# hibernate_hibernate <filename.m5ihib> <sourcefile> <source_md5> <exclude_stepback> +# ;# -> Bool (1 == successfull; 0 == failed) +# ;# This function also invokes dialog showing hibernation progress +# +# hibernate_resume <filename.m5ihib> <exclude_stepback> +# ;# -> Bool (1 == successfull; 0 == failed) +# ;# This function also invokes dialog showing progress +# +# Note: These functions are safe (checks for filename usability) +# -------------------------------------------------------------------------- + +class Hibernate { + ## COMMON + common version {1.0} ;# Float: Hibernate facility version + common hib_progress_d 0 ;# Int: Variable for hibernation progress dialog -- Memory + common hib_progress_s 0 ;# Int: Variable for hibernation progress dialog -- Program steps + common hib_abort 0 ;# Bool: Abort hibernation process + common expected ;# String: Expected next XML element + common take_data ;# Bool: Take element data on next parsing cycle + common current_element {} ;# String: Current XML element -- auxiliary variable for XML parser handler + common xml_tmp {} ;# Mixed: Auxiliary variable of any kind for XML parser handler + common source_file {} ;# String: Filename of the file from which the given file was generated + common exclude_stepback 0 ;# Bool: Exclude program steps + common counter 0 ;# Int: Counter of iterations for resume function for XML parser handler + common xdata_size 0 ;# Int: Size of external data memory + common eeprom_size 0 ;# Int: Size of data EEPROM + common sbs_length 0 ;# Int: Size of stepback stack + common file_variable ;# Bool: Checkbox variable for "Different filename" + common mcu_variable ;# Bool: Checkbox variable for "Different processor" + common xdata_variable ;# Int: RadioButton variable for "Different XDATA size" + common md5_variable ;# Bool: Checkbox variable for "Different MD5 hash" + # Big font for dialog "Program resumption" + common big_font [font create \ + -family {helvetica} \ + -weight bold -size -35 \ + ] + # Normal font for dialog "Program resumption" + common text_font [font create \ + -family {helvetica} \ + -weight bold -size -14 \ + ] + + ## PRIVATE + private variable parser ;# Object: Reference to active XML parser + private variable mem_prg_bar ;# Widget: Memory progress bar + private variable stb_prg_bar ;# Widget: Program steps progress bar + + private variable dlg_ok_but ;# Widget: Button "Ok" in dialog "Program resumption" + private variable dlg_result ;# Bool: Result of dialog "Program resumption" + private variable dlg_bits ;# List of Booleans: Differencies between hibernation file and engine config + + ## Dafety close hibernation/resumption progress dialog + # @return void + public method hibernate_close_progress_dialog {} { + set win {.hibernation_progress_dialog} + if {[winfo exists $win]} { + grab release $win + destroy $win + } + } + + ## Set maximum value for some progress bar in the hibernation progress dialog + # @parm String for_what - "data" == Memory ProgressBar; "step" == "Program steps" + # @parm Int value - New maximum value + # @return void + private method progress_dialog_set_max {for_what value} { + if {![winfo exists {.hibernation_progress_dialog}]} { + return + } + if {$value < 1} { + set value 1 + } + if {$for_what == {data}} { + $mem_prg_bar configure -maximum $value + } { + $stb_prg_bar configure -maximum $value + } + } + + ## Invoke hibernation / resumption progress dialog + # @parm String header - Window header + # @parm Int data_max - Maximum value for progress bar "Memory" (can be less than 1) + # @parm Int stepback_max - Maximum value for progress bar "Program steps" (can be less than 1) + # @return void + private method show_progress_dialog {header data_max stepback_max} { + # Reset NS variables related to this dialog + set hib_progress_d 0 + set hib_progress_s 0 + set hib_abort 0 + + # Adjust input values + if {$data_max < 1} { + set data_max 1 + } + incr data_max 2 + if {$stepback_max < 1} { + set stepback_max 1 + } + + # Create dialog window + set win [toplevel .hibernation_progress_dialog -class {Progress dialog} -bg {#EEEEEE}] + + # Create dialog header + pack [label $win.header \ + -text $header \ + -font [font create \ + -size -17 -weight {bold} \ + -family {helvetica} \ + ] \ + ] -fill x + + # Create progress bar "Memory" + set frame [frame $win.frame_0] + pack [label $frame.label -text {Memory}] -anchor w -padx 5 + set mem_prg_bar [ttk::progressbar $frame.progressbar \ + -mode determinate \ + -variable ::Hibernate::hib_progress_d \ + -maximum $data_max \ + ] + pack $mem_prg_bar -fill x + pack $frame -pady 5 -fill x -padx 5 + + # Create progress bar "Program steps" + set frame [frame $win.frame_1] + pack [label $frame.label -text {Program steps}] -anchor w -padx 5 + set stb_prg_bar [ttk::progressbar $frame.progressbar \ + -mode determinate \ + -variable ::Hibernate::hib_progress_s \ + -maximum $stepback_max \ + ] + pack $stb_prg_bar -fill x + pack $frame -pady 5 -fill x -padx 5 + + # Create button "Abort" + pack [ttk::button $win.abort_button \ + -text [mc "Abort"] \ + -compound left \ + -image ::ICONS::16::button_cancel \ + -command {set ::Hibernate::hib_abort 1} \ + ] -padx 10 -fill x + + # Configure dialog window + wm iconphoto $win ::ICONS::16::bar5 + wm title $win [mc "Hibernation progress"] + wm minsize $win 300 140 + wm protocol $win WM_DELETE_WINDOW "$this hibernate_close_progress_dialog" + wm transient $win . + update + catch { + grab $win + raise $win + } + } + + ## Hibernate running program + # @parm String filename - Target file + # @parm String sourcefile - Source file (current file in code editor) + # @parm String md5 - MD5 hash of the source file + # @parm Bool exclude_stepback - Exclude program steps + # @return Bool - 1 == Successful; 0 == Failed + public method hibernate_hibernate {filename sourcefile md5 exclude_stepback} { + # Try to open the destination file + if {[catch { + set file [open $filename w 420] + }]} { + return 0 + } + + # Determinate depth of stepback stack and size of XDATA memory + if {$exclude_stepback} { + set stacklength 0 + } { + set stacklength [$this simulator_get_SBS_len] + } + set xdata_size [$this cget -P_option_mcu_xdata] + set eeprom_size [lindex [$this cget -procData] 32] + + # Invoke progress dialog + show_progress_dialog \ + {Hibernating program} \ + [expr {($xdata_size + $eeprom_size) / 4096}] \ + [expr {$stacklength / 10}] + + # Write XML header to the destination file + puts -nonewline $file "<?xml version='1.0' encoding='utf-8'?>\n" + puts -nonewline $file "<!--\n" + puts -nonewline $file "\tThis is MCU 8051 IDE hibernation data file.\n" + puts -nonewline $file "\tIt does not contain program code, only data.\n\n" + puts -nonewline $file "\tPLEASE DO NOT EDIT THIS FILE MANUALY, BECAUSE\n" + puts -nonewline $file "\tBAD FORMATING OF THIS FILE WILL LEAD MCU 8051 IDE TO CRASH !\n" + puts -nonewline $file "-->\n" + + # Write DTD (Document Type Declaration) to the destination file + if {[file exists "${::LIB_DIRNAME}/../data/m5ihib.dtd"]} { + if {[catch { + set dtd [open "${::LIB_DIRNAME}/../data/m5ihib.dtd" r] + }]} { + puts stderr "Unable to open m5ihib.dtd, please check your installation." + } else { + puts -nonewline $file "<!DOCTYPE m5ihib \[\n\n" + while 1 { + if {[eof $dtd]} { + close $dtd + break + } + puts -nonewline $file "\t" + puts $file [gets $dtd] + } + puts -nonewline $file "\]>\n" + } + } + + # Write header + puts -nonewline $file "<m5ihib\n" + puts -nonewline $file "\tversion=\"$version\"\n" + puts -nonewline $file "\tdatetime=\"[clock format [clock seconds] -format {%D %T}]\"\n" + puts -nonewline $file "\tsource_file=\"$sourcefile\"\n" + puts -nonewline $file "\tprocessor=\"[$this cget -P_option_mcu_type]\"\n" + puts -nonewline $file "\txdata=\"$xdata_size\"\n" + puts -nonewline $file "\teeprom=\"$eeprom_size\"\n" + puts -nonewline $file "\tmd5=\"$md5\">\n" + + ## Write current state of simulator engine + puts -nonewline $file "\t<currentstate>\n" + # Internal data memory + puts -nonewline $file "\t\t<iram>\n\t\t\t" + for {set i 0; set j 0} {$i < [lindex [$this cget -procData] 3]} {incr i; incr j} { + if {$j > 7} { + set j 0 + puts -nonewline $file "\n\t\t\t" + } + puts -nonewline $file [$this getDataDEC $i] + puts -nonewline $file "\t" + } + incr hib_progress_d + puts -nonewline $file "\n\t\t</iram>\n" + # Expanded data memory + puts -nonewline $file "\t\t<eram>\n\t\t\t" + for {set i 0; set j 0} {$i < [lindex [$this cget -procData] 8]} {incr i; incr j} { + if {$j > 7} { + set j 0 + puts -nonewline $file "\n\t\t\t" + } + puts -nonewline $file [$this getEramDEC $i] + puts -nonewline $file "\t" + } + incr hib_progress_d + puts -nonewline $file "\n\t\t</eram>\n" + # External data memory + puts -nonewline $file "\t\t<xram>\n\t\t\t" + set i 0 + set j 0 + for {set m 0} {$m < 8} {incr m} { + for {set k 0} {$i < $xdata_size && $k < 4096} {incr k} { + if {$j > 7} { + set j 0 + puts -nonewline $file "\n\t\t\t" + } + puts -nonewline $file [$this getXdataDEC $i] + puts -nonewline $file "\t" + incr i + incr j + + if {$hib_abort} { + catch { + file delete -force $filename + } + hibernate_close_progress_dialog + return 1 + } + } + incr hib_progress_d + update + } + puts -nonewline $file "\n\t\t</xram>\n" + # Special function registers + puts -nonewline $file "\t\t<eeprom>\n\t\t\t" + set i 0 + set j 0 + for {set m 0} {$m < 8} {incr m} { + for {set k 0} {$i < $eeprom_size && $k < 4096} {incr k} { + if {$j > 7} { + set j 0 + puts -nonewline $file "\n\t\t\t" + } + puts -nonewline $file [$this getEepromDEC $i] + puts -nonewline $file "\t" + incr i + incr j + + if {$hib_abort} { + catch { + file delete -force $filename + } + hibernate_close_progress_dialog + return 1 + } + } + incr hib_progress_d + update + } + puts -nonewline $file "\n\t\t</eeprom>\n" + # Special function registers + puts -nonewline $file "\t\t<sfr>\n" + puts -nonewline $file "\t\t\t<addresses>\n\t\t\t\t" + set sfr [$this simulator_get_avaliable_sfr] + set j 0 + foreach addr $sfr { + if {$j > 6} { + set j 0 + puts -nonewline $file "\n\t\t\t\t" + } + puts -nonewline $file $addr + puts -nonewline $file "\t" + incr j + } + puts -nonewline $file "\n\t\t\t</addresses>\n" + puts -nonewline $file "\t\t\t<values>\n\t\t\t\t" + set j 0 + foreach addr $sfr { + if {$j > 6} { + set j 0 + puts -nonewline $file "\n\t\t\t\t" + } + puts -nonewline $file [$this getSfrDEC $addr] + puts -nonewline $file "\t" + incr j + } + puts -nonewline $file "\n\t\t\t</values>\n" + puts -nonewline $file "\t\t</sfr>\n" + # Special engine configuration string + puts -nonewline $file "\t\t<special>\n\t\t\t" + puts -nonewline $file [$this simulator_get_special] + puts -nonewline $file "\n\t\t</special>\n" + puts -nonewline $file "\t</currentstate>\n" + + ## Write content of list of active interrupts + puts -nonewline $file "\t<subprograms count=\"[$this subprograms_get_count]\">\n" + foreach sub [$this subprograms_get_formated_content] { + set source [lindex $sub 0] + set target [lindex $sub 1] + set type [lindex $sub 2] + puts -nonewline $file "\t\t<sub source=\"$source\" target=\"$target\" type=\"$type\"/>\n" + } + puts -nonewline $file "\t</subprograms>\n" + + ## Write stepback stack + puts -nonewline $file "\t<stepback stacklength=\"$stacklength\">\n" + for {set i 0} {$i < $stacklength} {incr i} { + puts -nonewline $file "\t\t<step>\n" + puts -nonewline $file "\t\t\t<spec>\n\t\t\t\t" + puts -nonewline $file [$this simulator_hib_get_SB_spec $i] + puts -nonewline $file "\n\t\t\t</spec><normal>\n" + set stepback_normal [$this simulator_hib_get_SB_norm $i] + set norm_len [llength $stepback_normal] + for {set j 0} {$j < $norm_len} {incr j} { + puts -nonewline $file "\t\t\t\t<reg type=\"" + puts -nonewline $file [lindex $stepback_normal [list $j 0]] + puts -nonewline $file "\" addr=\"" + puts -nonewline $file [lindex $stepback_normal [list $j 1]] + puts -nonewline $file "\" val=\"" + puts -nonewline $file [lindex $stepback_normal [list $j 2]] + puts -nonewline $file "\"/>\n" + } + puts -nonewline $file "\t\t\t</normal>\n" + puts -nonewline $file "\t\t</step>\n" + + if {!($i % 10)} { + incr hib_progress_s + update + } + if {$hib_abort} { + catch { + file delete -force $filename + } + hibernate_close_progress_dialog + return 1 + } + } + puts -nonewline $file "\t</stepback>\n" + puts -nonewline $file "</m5ihib>\n" + + # Close progress dialog and the destination file + hibernate_close_progress_dialog + if {[catch {close $file}]} { + return 0 + } { + return 1 + } + } + + ## Resume hibernated program + # @parm String filename - Source file (XML containing hibernation data) + # @parm Bool exclude_stepback - Exclude program steps for step back function + # @return Int - Exit code + # 0 - Success + # 1 - Unable to open the given file + # 2 - Unable to parse the given file + public method hibernate_resume {filename _exclude_stepback} { + # Initialize parser variables + set expected {m5ihib} + set take_data 0 + set counter 0 + set sbs_length 0 + set current_element {} + set xml_tmp {} + set source_file $filename + set exclude_stepback $_exclude_stepback + + set exit_code 0 + + # Open hibernation data file + if {[catch { + set file [open $filename {r}] + }]} { + return 1 + } + + # Show progress dialog + show_progress_dialog {Resuming hibernated program} 1 1 + + # Create XML parser object + if {[catch { + set parser [::xml::parser -final 1 -ignorewhitespace 1 \ + -elementstartcommand [list $this hibernate_xml_parser_element] \ + -characterdatacommand [list $this hibernate_xml_parser_data] \ + ] + }]} { + hibernate_close_progress_dialog + tk_messageBox \ + -type ok -icon error -parent . \ + -title "::xml::parser error" \ + -message "Unknown error occured in XML parser library,\nplease try to reinstall package \"tdom\"." + return 2 + } + + # Prepare simulator engine + if {!$exclude_stepback} { + $this stepback_discard_stack + } + + # Start XML parser + $this set_ignore_warnings_related_to_changes_in_SFR 1 + if {[catch { + $parser parse [read $file] + } result]} then { + puts stderr $result + set exit_code 2 + } else { + if {$xml_tmp != {}} { + $this simulator_hib_append_SB_norm $xml_tmp + } + } + + # Close the file and free the parser + if {[catch { + close $file + }]} { + set exit_code 1 + } + catch { + $parser free + } + + # Synchronize simulator GUI + $this clear_graph + $this Simulator_sync + $this interrupt_monitor_reevaluate + $this stopwatch_refresh + set interrupts_in_progress [$this simulator_get_interrupts_in_progress_pb] + if {[llength $interrupts_in_progress]} { + simulator_Sbar [mc "Interrupt at vector 0x%s " [format %X [$this intr2vector [lindex $interrupts_in_progress end]]]] 1 $this + } { + simulator_Sbar {} 0 $this + } + set lineNum [$this simulator_getCurrentLine] + if {$lineNum != {}} { + $this move_simulator_line $lineNum + } { + $this editor_procedure {} unset_simulator_line {} + } + ::X::stepback_button_set_ena [$this simulator_get_SBS_len] + + # Cleanup + set xml_tmp {} + hibernate_close_progress_dialog + $this set_ignore_warnings_related_to_changes_in_SFR 0 + return $exit_code + } + + ## Element XML parser handler for method hibernate_resume + # @parm String arg1 - name of the element + # @parm List attrs - list of attributes '{attr0 val0 attr1 val1 ...}' + # @return void + public method hibernate_xml_parser_element {arg1 attrs} { + if {$hib_abort} { + $parser free + return + } + + set current_element $arg1 + if {[lsearch $expected $current_element] == -1} { + error "Unexpected element: `$current_element'" + } + + switch -- $arg1 { + {m5ihib} { ;# ROOT ELEMENT + set expected {currentstate} + set take_data 0 + + # Read the file header + set len [llength $attrs] + set xml_tmp [list {} {} {} {} {} {} {}] + for {set i 0} {$i < $len} {incr i} { + set arg [lindex $attrs $i] + incr i + set val [lindex $attrs $i] + switch -- $arg { + {version} {lset xml_tmp 0 $val} + {datetime} {lset xml_tmp 1 $val} + {source_file} {lset xml_tmp 2 $val} + {processor} {lset xml_tmp 3 $val} + {xdata} {lset xml_tmp 4 $val} + {eeprom} {lset xml_tmp 5 $val} + {md5} {lset xml_tmp 6 $val} + } + } + + # Check if all of required fields are present + foreach str $xml_tmp { + if {![string length $str]} { + error "XML tag <m5ihib>: Some required attributes missing" + } + } + + # Check for minimum required version + if {$version < [lindex $xml_tmp 0]} { + tk_messageBox \ + -parent . \ + -type ok \ + -icon warning \ + -title [mc "Fatal error"] \ + -message [mc "Version of this M5IHIB file is higher than %s\nUnable to continue." $version] + set hib_abort 1 + } + + # Set maximum for ProgressBar "Memory" and set size of XDATA memory + set xdata_size [lindex $xml_tmp 4] + set eeprom_size [lindex $xml_tmp 5] + progress_dialog_set_max data [expr {$xdata_size / 4096}] + + # Check for remaining requirements + check_file_usability + + set xml_tmp {} + + } + {currentstate} { ;# Current state of MCU + set expected {iram} + set take_data 0 + } + {iram} { ;# Internal data memory in decimal + set expected {eram} + set take_data 1 + } + {eram} { ;# Expanded data memory in decimal + set expected {xram} + set take_data 1 + } + {xram} { ;# External data memory in decimal + set expected {eeprom} + set take_data 1 + set counter 0 + } + {eeprom} { ;# Data EEPROM in decimal + set expected {sfr} + set take_data 1 + set counter 0 + } + {sfr} { ;# Special function registers + set expected {addresses} + set take_data 0 + } + {addresses} { ;# SFR decimal addresses in the same order as in tag values + set expected {values} + set take_data 1 + } + {values} { ;# SFR decimal values in the same order as in tag values + set expected {special} + set take_data 1 + } + {special} { ;# Special engine variables + set expected {subprograms} + set take_data 1 + + if {$exclude_stepback} { + set hib_abort 1 + } + } + {subprograms} { ;# Content of list of active interrupts + set expected {stepback sub} + set take_data 0 + + $this subprograms_clear + } + {sub} { ;# Active interrupt + set expected {stepback sub} + set take_data 0 + + set source {} + set target {} + set type {} + + set len [llength $attrs] + for {set i 0} {$i < $len} {incr i} { + switch -- [lindex $attrs $i] { + {type} { + incr i + set type [lindex $attrs $i] + } + {source} { + incr i + set source [lindex $attrs $i] + } + {target} { + incr i + set target [lindex $attrs $i] + } + default { + incr i + } + } + } + if {$source != {} && $target != {} && $type != {}} { + $this subprograms_call $type $source $target + } { + error "Invalid argument set in tag <step>" + } + } + {stepback} { ;# Stack for stepback function (backward stepping) + set expected {step} + set take_data 0 + set counter 0 + + set len [llength $attrs] + for {set i 0} {$i < $len} {incr i 2} { + if {[lindex $attrs $i] == {stacklength}} { + incr i + set stacklength [lindex $attrs $i] + $this simulator_set_SBS_len $stacklength + progress_dialog_set_max stepback [expr {$stacklength / 10}] + break + } { + incr i + } + } + } + {step} { ;# One program step + set expected {spec} + set take_data 0 + } + {spec} { ;# Special engine variables + set expected {normal} + set take_data 1 + } + {normal} { ;# Ordinary registers + set expected {step reg} + set take_data 0 + + if {$xml_tmp != {}} { + $this simulator_hib_append_SB_norm $xml_tmp + } + set xml_tmp {} + } + {reg} { ;# One register + set expected {reg step} + set take_data 0 + + set reg [list {} {} {}] + set len [llength $attrs] + + for {set i 0} {$i < $len} {incr i} { + set arg [lindex $attrs $i] + incr i + set val [lindex $attrs $i] + + switch -- $arg { + {type} {lset reg 0 $val} + {addr} {lset reg 1 $val} + {val} {lset reg 2 $val} + } + } + + lappend xml_tmp $reg + } + } + } + + ## Data XML parser handler for method hibernate_resume + # @parm String arg1 - content of the element + # @return void + public method hibernate_xml_parser_data {arg1} { + if {$hib_abort} { + $parser free + return + } + + # Take data only if they were expected + if {!$take_data} {return} + set take_data 0 + + switch -- $current_element { + {iram} { ;# Internal data memory in decimal + for {set i 0} {$i < [lindex [$this cget -procData] 3]} {incr i} { + $this setDataDEC $i [lindex $arg1 $i] + } + incr hib_progress_d + } + {eram} { ;# Expanded data memory in decimal + for {set i 0} {$i < [lindex [$this cget -procData] 8]} {incr i} { + $this setEramDEC $i [lindex $arg1 $i] + } + incr hib_progress_d + } + {xram} { ;# External data memory in decimal + set addr 0 + for {set m 0} {$m < 8} {incr m} { + for {set k 0} {$addr < $xdata_size && $k < 4096} {incr k} { + $this setXdataDEC $addr [lindex $arg1 $addr] + incr addr + + if {$hib_abort} { + hibernate_close_progress_dialog + return 1 + } + } + incr hib_progress_d + update + } + } + {eeprom} { ;# Data EEPROM in decimal + set addr 0 + for {set m 0} {$m < 8} {incr m} { + for {set k 0} {$addr < $eeprom_size && $k < 4096} {incr k} { + $this setEepromDEC $addr [lindex $arg1 $addr] + incr addr + + if {$hib_abort} { + hibernate_close_progress_dialog + return 1 + } + } + incr hib_progress_d + update + } + } + {addresses} { ;# SFR decimal addresses in the same order as in tag values + set xml_tmp $arg1 + } + {values} { ;# SFR decimal values in the same order as in tag values + foreach addr $xml_tmp val $arg1 { + $this setSfr_directly $addr $val + } + set xml_tmp {} + } + {special} { ;# Special engine variables + $this simulator_set_special $arg1 + } + {spec} { ;# Special engine variables for stepback funtion + $this simulator_hib_append_SB_spec $arg1 + + incr counter + if {!($counter % 10)} { + incr hib_progress_s + update + } + } + } + } + + ## Check if the current hibernation file is usable and invoke dialog to configure simulator engine + # @return void + private method check_file_usability {} { + # Determinate full name of source file and its MD5 hash + set sourcefile [list \ + [$this cget -projectPath] \ + [$this cget -P_option_main_file] \ + ] + if {[lindex $sourcefile 1] == {}} { + set sourcefile [$this editor_procedure {} getFileName {}] + } + set sourcefile_md5 {} + catch { + set sourcefile_md5 [::md5::md5 -hex -file \ + [file join [lindex $sourcefile 0] [lindex $sourcefile 1]]] + } + + ## Determinate list of differencies + set differences [list 0 0 0 0] + if {[lindex $xml_tmp 2] != [lindex $sourcefile 1]} { + lset differences 0 1 + } + if {[lindex $xml_tmp 3] != [$this cget -P_option_mcu_type]} { + lset differences 1 1 + } + if {[lindex $xml_tmp 4] != [$this cget -P_option_mcu_xdata]} { + lset differences 2 1 + } + if {[lindex $xml_tmp 6] != $sourcefile_md5} { + lset differences 3 1 + } + + # If there are some differencies -> invoke dialog + foreach bool $differences { + if {$bool} { + if {[ask_user_what_to_do $differences]} { + set hib_abort 1 + } + break + } + } + } + + ## Invoke dialog showing differencies between the hibernation file and engine configuration + # @parm List differences - + # @return Bool - 1 == abort process; 0 == keep alive + private method ask_user_what_to_do {differences} { + # Set NS variables + set file_variable 1 + set mcu_variable 1 + set xdata_variable 1 + set md5_variable 1 + + set win [toplevel .hibernation_bad_file_dialog -class {Error dialog} -bg {#EEEEEE}] + set dlg_result 1 + set dlg_bits $differences + + # Create dialog header + pack [label $win.header_label \ + -font $text_font \ + -text [mc "The following problems must be \nresolved before program resumption"] \ + ] -fill x -padx 10 -pady 5 + + # Create main frame + set main_frame [frame $win.main_frame] + + # MCU is different + set num 0 + if {[lindex $differences 1]} { + incr num + set frame [dialog_create_item $num $main_frame [mc "This file is indented for %s but the current MCU is %s" [lindex $xml_tmp 3] [$this cget -P_option_mcu_type]]] + pack [checkbutton $frame.chbut \ + -text [mc "Set current MCU to %s" [lindex $xml_tmp 3]] \ + -variable ::Hibernate::mcu_variable \ + -command "$this hibernation_chbut_rabut_command" \ + ] -anchor w + } + # XDATA is different + if {[lindex $differences 2]} { + incr num + set frame [dialog_create_item $num $main_frame [mc "This file contains %s B of external data memory but but your processor has %s B" [lindex $xml_tmp 4] [$this cget -P_option_mcu_xdata]]] + pack [radiobutton $frame.rabut0 \ + -text [mc "Set current XDATA capacity to %s B" [lindex $xml_tmp 4]] \ + -variable ::Hibernate::xdata_variable -value 1 \ + -command "$this hibernation_chbut_rabut_command" \ + ] -anchor w + pack [radiobutton $frame.rabut1 \ + -text [mc "Ignore this difference"] \ + -variable ::Hibernate::xdata_variable -value 2 \ + -command "$this hibernation_chbut_rabut_command" \ + ] -anchor w + } + # MD5 is different + if {[lindex $differences 3]} { + incr num + set frame [dialog_create_item $num $main_frame [mc "Current file (%s) has different MD5 hash than MD5 recorded in this hibernation file" [lindex [$this editor_procedure {} getFileName {}] 1]]] + pack [checkbutton $frame.chbut \ + -text [mc "Ignore this difference"] \ + -variable ::Hibernate::md5_variable \ + -command "$this hibernation_chbut_rabut_command" \ + ] -anchor w + } + # Filename is different + if {[lindex $differences 0]} { + incr num + set frame [dialog_create_item $num $main_frame [mc "This hibernation file was generated from \"%s\" but current file is \"%s\"" [lindex $xml_tmp 2] [lindex [$this editor_procedure {} getFileName {}] 1]]] + pack [checkbutton $frame.chbut \ + -text [mc "Ignore this difference"] \ + -variable ::Hibernate::file_variable \ + -command "$this hibernation_chbut_rabut_command" \ + ] -anchor w + } + + pack $main_frame -fill both -expand 1 + + # Create buttons "Ok" and "Cancel" + set button_frame [frame $win.button_frame] + set dlg_ok_but [ttk::button $button_frame.button_ok \ + -text [mc "Ok"] \ + -command "$this hibernation_cls_dlg 0" \ + -compound left \ + -image ::ICONS::16::ok \ + ] + pack $dlg_ok_but -side left + pack [ttk::button $button_frame.button_cancel \ + -text [mc "Cancel"] \ + -command "$this hibernation_cls_dlg 1" \ + -compound left \ + -image ::ICONS::16::button_cancel \ + ] -side left + pack $button_frame -side bottom -anchor e -padx 10 -pady 5 + + # Configure dialog window + wm iconphoto $win ::ICONS::16::resume + wm title $win [mc "Program resumption"] + wm minsize $win 480 200 + wm protocol $win WM_DELETE_WINDOW " + grab release $win + destroy $win" + wm transient $win .hibernation_progress_dialog + + update + catch { + grab $win + raise $win + } + focus -force $dlg_ok_but + tkwait window $win + return $dlg_result + } + + ## Create one item in dialog generated by proc. ask_user_what_to_do + # @parm Int number - Item number + # @parm Widget mainframe - Frame where to pack this item + # @parm String text - Item text + # @return Widget - Frame "Options:" + private method dialog_create_item {number mainframe text} { + # Create horizontal separator + pack [ttk::separator $mainframe.sep_${number} \ + -orient horizontal \ + ] -fill x -pady 7 -expand 1 -padx 5 + + # Create label with number + set local_frame [frame $mainframe.frame_${number}] + pack [label $local_frame.lbl \ + -font $big_font -text "${number}." \ + ] -side left -anchor n -padx 3 + set right_frame [frame $local_frame.right] + + # Create text widget for the given message + set text_wdg [text $right_frame.top_text \ + -width 0 -height 3 -wrap word -bd 0 \ + -relief flat -bg {#EEEEEE} \ + -font $text_font -cursor left_ptr \ + ] + $text_wdg insert end $text + $text_wdg configure -state disabled + pack $text_wdg -fill both -expand 1 -pady 3 + + # Create frame "Options:" + pack [label $right_frame.opt_lbl -text [mc "Options:"]] -anchor w -padx 10 + set options_frame [frame $right_frame.options] + + # Pack parts of this item and return frame "Options:" + pack $options_frame -padx 35 -anchor w + pack $right_frame -side left -fill both -expand 1 + pack $local_frame -fill both -expand 1 -padx 10 + return $options_frame + } + + ## Command for checkbuttons and radiobuttons in options frame + # Enables / disables Ok button + # @return void + public method hibernation_chbut_rabut_command {} { + if {$file_variable && $mcu_variable && $xdata_variable && $md5_variable} { + $dlg_ok_but configure -state normal + } { + $dlg_ok_but configure -state disabled + } + } + + ## Close dialog with some result + # @parm Mixed new_result - Dialog result + # @return void + public method hibernation_cls_dlg {new_result} { + if {!$new_result} { + # Adjust processor type + if {[lindex $dlg_bits 1]} { + ::X::change_processor [lindex $xml_tmp 3] + } + + # Adjust size of external data memory + if {[lindex $dlg_bits 2]} { + # Set new value + if {$xdata_variable == 1} { + if {[lindex [$this cget -procData] 0] == {yes}} { + $this configure -P_option_mcu_xdata $xdata_size + ::X::close_hexedit xdata $this + $this simulator_resize_xdata_memory $xdata_size + } { + set xdata_size 0 + } + + # Ignore + } elseif {$xdata_variable == 2} { + set xdata_size [$this cget -P_option_mcu_xdata] + } + } + } + + # Set dialog result and destroy it + set dlg_result $new_result + + catch { + grab release .hibernation_bad_file_dialog + } + catch { + destroy .hibernation_bad_file_dialog + } + } +} |