9.7.1 Debug Scripting

The debug scripting interface is function-based and depends on certain named functions defined in a Python file. The function will then be called when the corresponding event occurs inside Microchip Studio.

Attention:

Error checking is kept at a minimum for the functions exported into the Python environment, so the time used on initialization during ordinary sessions is kept low, meaning that there are many ways to crash Microchip Studio through this interface.

To load a Python file, place a file named debughooks.py in the Debug folder of your project, next to the ELF file, or one folder up where the project file is. It is also possible to place this file inside the Microchip Studio installation directory to load the script for all projects.

Note: The Python file is loaded and compiled when a project is launched, so changes to the Python file during a debug session will not be active until the next debug session is started. The Python file is running in an IronPython context, with full access to .NET and a Python 2.7 runtime. See ironpython.net/documentation/dotnet/ for more information on the runtime.
Microchip Studio will try loading the functions shown below with their function signature.
def should_process_breakpoint(studio_interface, 
                              breakpoint_address, 
                              breakpoint_id, 
                              obj):
	"""
	Called to determine if a breakpoint should cause Microchip Studio to enter debug mode.

	If this function returns False, Microchip Studio will not break at the breakpoint.
	"""
	
	return True


def has_processed_breakpoint(studio_interface, 
                             breakpoint_address, 
                             breakpoint_id, 
                             obj):
	"""
	This function is called if Microchip Studio is breaking at a breakpoint. 
	The GUI is now in halted mode.
	"""
	
	pass


def on_reset(studio_interface, 
             reset_address):
	"""
	This function is called when the target is reset. The address 
	where the reset went to is 'reset_address'.
	"""
	
	pass


def on_eval_expr(studio_interface, 
                 expression):
	"""
	This function is called for each expression that is evaluated in Microchip Studio. 
	
	This includes the watch window and other windows that show data from the target. 
	Pass the 'expression' string through to evaluate it, or return another expression 
	to be evaluated to override the expression. This override is not visible in the 
	Microchip Studio GUI.
	"""
	
	return expression

Note: Microchip Studio expects all these functions to be available if the script has been found and loaded correctly. If, for instance, the should_process_breakpoint is undefined, breakpoints might start to misbehave as the return value of an undefined function is in itself undefined.

The main interface back into the Microchip Studio is the studio_interface object is shown in the code above. This object contains some functions to show messages and do target interaction.

The Print function in the studio_interface object shows text in the output window inside Microchip Studio. The function takes two arguments; the string to print and thethe tab name in the output window. The example below prints all the evaluated expressions to the Expressions tab.
def on_eval_expr(studio_interface, expression):
	studio_interface.Print("Evaluating {}".format(expression), "Expressions")
	return expression
Note: The severity level of text sent through Print is set to INFO, meaning that the output may be masked by Microchip Studio. To lower the threshold, go to Tools > Tools, select Status Management, and set the Display Threshold to INFO.

Use the ExecStmt function in the studio_interface object to execute statements in the debugger, which can, for instance, be used to set variables. See MSDN Debugger.ExecuteStatement Method for more information.

The WriteMemory and ReadMemory are symmetric functions for reading and writing memory on the target. It is important to use a System.Array[System.Byte] object to pass the data between the script and Microchip Studio.

import System

def should_process_breakpoint(studio_interface, 
                              breakpoint_address, 
                              breakpoint_id, 
                              obj):
	vals = System.Array[System.Byte]([1, 2, 3, 4, 5, 6, 7, 8, 9])

	studio_interface.WriteMemory(data=vals, adr=0, type="eeprom")

	ret = studio_interface.ReadMemory(adr=0, type="eeprom", count=9)

	studio_interface.Print("ret == vals => {!r}".format(ret == vals), "Python")
	return True
The CalcNumericValue is a shorthand for the CalcValue call. It will return the numeric value of the symbol or the provided default value if the function fails to retrieve the value of the symbol.
def should_process_breakpoint(studio_interface, 
                              breakpoint_address, 
                              breakpoint_id, 
                              obj):
	a = studio_interface.CalcNumericValue("a", 0)
	if a == 0:
	 studio_interface.Print("a was 0 or default", "Value scripts")
	else:
	 studio_interface.Print("a = {}".format(a), "Value scripts")
	return True
The CalcValue function is used to retrieve information about a symbol in the scope where the target code is running. The return value of this call is a list of information containing the address of the symbol, symbol information, and value. The objects sent to this list contain all known information about a symbol, but the most helpful field is the last element, which contains the value of the evaluated symbol.
def should_process_breakpoint(studio_interface, 
                              breakpoint_address, 
                              breakpoint_id, 
                              obj):
	a = studio_interface.CalcValue("a")
	# a now contains all information about the variable a. 
	# It is a list with the following members:
	# a = [
	#   <Atmel.VsIde.AvrStudio.Services.TargetService.TCF.Services.ValueInfo>, 
	#   <Atmel.VsIde.AvrStudio.Services.TargetService.TCF.Services.SymbolInfo>, 
	#   <Atmel.VsIde.AvrStudio.Services.TargetService.TCF.Services.ExpressionInfo>, 
	#   '1' ] <-- This is the value of the symbol as a string, here it had the value 1
	
	studio_interface.Print("Value of a = {}".format(a[3]), "Value Scripts")
	return True
Note: The different objects returned by the CalcValue call contain objects that are either internal or documented in the Microchip Studio SDK. Use the python dir() command to look at the exported fields.