104 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			104 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import logging
 | |
| import subprocess
 | |
| 
 | |
| 
 | |
| class CubeProgrammer:
 | |
|     """STM32 Cube Programmer cli wrapper"""
 | |
| 
 | |
|     def __init__(self, config={}):
 | |
|         assert isinstance(config, dict)
 | |
|         # Params base
 | |
|         self.params = []
 | |
|         # Connect params
 | |
|         connect = []
 | |
|         if "port" in config and config["port"]:
 | |
|             connect.append(f"port={config['port']}")
 | |
|         else:
 | |
|             connect.append(f"port=swd")
 | |
|         if "serial" in config and config["serial"]:
 | |
|             connect.append(f"sn={config['serial']}")
 | |
|         self.params.append("-c " + " ".join(connect))
 | |
|         # Other params
 | |
|         if "params" in config:
 | |
|             self.params += config["params"]
 | |
|         # logging
 | |
|         self.logger = logging.getLogger()
 | |
| 
 | |
|     def _execute(self, args):
 | |
|         try:
 | |
|             params = [
 | |
|                 "STM32_Programmer_CLI",
 | |
|                 "-q",
 | |
|                 *self.params,
 | |
|                 *args,
 | |
|             ]
 | |
|             self.logger.debug(f"_execute: {params}")
 | |
|             output = subprocess.check_output(params)
 | |
|         except subprocess.CalledProcessError as e:
 | |
|             if e.output:
 | |
|                 print("Process output:\n", e.output.decode())
 | |
|             print("Process return code:", e.returncode)
 | |
|             raise e
 | |
|         assert output
 | |
|         return output.decode()
 | |
| 
 | |
|     def getVersion(self):
 | |
|         output = self._execute(["--version"])
 | |
| 
 | |
|     def checkOptionBytes(self, option_bytes):
 | |
|         output = self._execute(["-ob displ"])
 | |
|         ob_correct = True
 | |
|         for line in output.split("\n"):
 | |
|             line = line.strip()
 | |
|             if not ":" in line:
 | |
|                 self.logger.debug(f"Skipping line: {line}")
 | |
|                 continue
 | |
|             key, data = line.split(":", 1)
 | |
|             key = key.strip()
 | |
|             data = data.strip()
 | |
|             if not key in option_bytes.keys():
 | |
|                 self.logger.debug(f"Skipping key: {key}")
 | |
|                 continue
 | |
|             self.logger.debug(f"Processing key: {key} {data}")
 | |
|             value, comment = data.split(" ", 1)
 | |
|             value = value.strip()
 | |
|             comment = comment.strip()
 | |
|             if option_bytes[key][0] != value:
 | |
|                 self.logger.error(
 | |
|                     f"Invalid OB: {key} {value}, expected: {option_bytes[key][0]}"
 | |
|                 )
 | |
|                 ob_correct = False
 | |
|         return ob_correct
 | |
| 
 | |
|     def setOptionBytes(self, option_bytes):
 | |
|         options = []
 | |
|         for key, (value, attr) in option_bytes.items():
 | |
|             if "w" in attr:
 | |
|                 options.append(f"{key}={value}")
 | |
|         self._execute(["-ob", *options])
 | |
|         return True
 | |
| 
 | |
|     def flashBin(self, address, filename):
 | |
|         self._execute(
 | |
|             [
 | |
|                 "-d",
 | |
|                 filename,
 | |
|                 f"{address}",
 | |
|             ]
 | |
|         )
 | |
| 
 | |
|     def flashCore2(self, address, filename):
 | |
|         self._execute(
 | |
|             [
 | |
|                 "-fwupgrade",
 | |
|                 filename,
 | |
|                 f"{address}",
 | |
|             ]
 | |
|         )
 | |
| 
 | |
|     def deleteCore2RadioStack(self):
 | |
|         self._execute(["-fwdelete"])
 | |
| 
 | |
|     def resetTarget(self):
 | |
|         self._execute([])
 | 
