1# -*- coding: utf-8 -*- 2 3# Copyright (c) 2021 Detlev Offenbach <detlev@die-offenbachs.de> 4# 5 6""" 7Module implementing the device interface class for generic MicroPython devices 8(i.e. those devices not specifically supported yet). 9""" 10 11import os 12 13from E5Gui import E5MessageBox 14 15from .MicroPythonDevices import MicroPythonDevice 16from .MicroPythonWidget import HAS_QTCHART 17 18import Preferences 19import Utilities 20 21 22class GenericMicroPythonDevice(MicroPythonDevice): 23 """ 24 Class implementing the device interface for generic MicroPython boards. 25 """ 26 def __init__(self, microPythonWidget, deviceType, vid, pid, parent=None): 27 """ 28 Constructor 29 30 @param microPythonWidget reference to the main MicroPython widget 31 @type MicroPythonWidget 32 @param deviceType device type assigned to this device interface 33 @type str 34 @param vid vendor ID 35 @type int 36 @param pid product ID 37 @type int 38 @param parent reference to the parent object 39 @type QObject 40 """ 41 super().__init__( 42 microPythonWidget, deviceType, parent) 43 44 self.__directAccess = False 45 self.__deviceVolumeName = "" 46 self.__workspace = "" 47 self.__deviceName = "" 48 49 for deviceData in Preferences.getMicroPython("ManualDevices"): 50 if ( 51 deviceData["vid"] == vid and 52 deviceData["pid"] == pid 53 ): 54 self.__deviceVolumeName = deviceData["data_volume"] 55 self.__directAccess = bool(deviceData["data_volume"]) 56 self.__deviceName = deviceData["description"] 57 58 if self.__directAccess: 59 self.__workspace = self.__findWorkspace() 60 61 def setButtons(self): 62 """ 63 Public method to enable the supported action buttons. 64 """ 65 super().setButtons() 66 self.microPython.setActionButtons( 67 run=True, repl=True, files=True, chart=HAS_QTCHART) 68 69 if self.__directAccess and self.__deviceVolumeMounted(): 70 self.microPython.setActionButtons(open=True, save=True) 71 72 def deviceName(self): 73 """ 74 Public method to get the name of the device. 75 76 @return name of the device 77 @rtype str 78 """ 79 return self.__deviceName 80 81 def canStartRepl(self): 82 """ 83 Public method to determine, if a REPL can be started. 84 85 @return tuple containing a flag indicating it is safe to start a REPL 86 and a reason why it cannot. 87 @rtype tuple of (bool, str) 88 """ 89 return True, "" 90 91 def canStartPlotter(self): 92 """ 93 Public method to determine, if a Plotter can be started. 94 95 @return tuple containing a flag indicating it is safe to start a 96 Plotter and a reason why it cannot. 97 @rtype tuple of (bool, str) 98 """ 99 return True, "" 100 101 def canRunScript(self): 102 """ 103 Public method to determine, if a script can be executed. 104 105 @return tuple containing a flag indicating it is safe to start a 106 Plotter and a reason why it cannot. 107 @rtype tuple of (bool, str) 108 """ 109 return True, "" 110 111 def runScript(self, script): 112 """ 113 Public method to run the given Python script. 114 115 @param script script to be executed 116 @type str 117 """ 118 pythonScript = script.split("\n") 119 self.sendCommands(pythonScript) 120 121 def canStartFileManager(self): 122 """ 123 Public method to determine, if a File Manager can be started. 124 125 @return tuple containing a flag indicating it is safe to start a 126 File Manager and a reason why it cannot. 127 @rtype tuple of (bool, str) 128 """ 129 return True, "" 130 131 def supportsLocalFileAccess(self): 132 """ 133 Public method to indicate file access via a local directory. 134 135 @return flag indicating file access via local directory 136 @rtype bool 137 """ 138 return self.__deviceVolumeMounted() 139 140 def __deviceVolumeMounted(self): 141 """ 142 Private method to check, if the device volume is mounted. 143 144 @return flag indicated a mounted device 145 @rtype bool 146 """ 147 if self.__workspace and not os.path.exists(self.__workspace): 148 self.__workspace = "" # reset 149 150 return ( 151 self.__directAccess and 152 self.__deviceVolumeName in self.getWorkspace(silent=True) 153 ) 154 155 def getWorkspace(self, silent=False): 156 """ 157 Public method to get the workspace directory. 158 159 @param silent flag indicating silent operations 160 @type bool 161 @return workspace directory used for saving files 162 @rtype str 163 """ 164 if self.__directAccess: 165 if self.__workspace: 166 # return cached entry 167 return self.__workspace 168 else: 169 self.__workspace = self.__findWorkspace(silent=silent) 170 return self.__workspace 171 else: 172 return super().getWorkspace() 173 174 def __findWorkspace(self, silent=False): 175 """ 176 Private method to find the workspace directory. 177 178 @param silent flag indicating silent operations 179 @type bool 180 @return workspace directory used for saving files 181 @rtype str 182 """ 183 # Attempts to find the path on the filesystem that represents the 184 # plugged in board. 185 deviceDirectories = Utilities.findVolume(self.__deviceVolumeName, 186 findAll=True) 187 188 if deviceDirectories: 189 if len(deviceDirectories) == 1: 190 return deviceDirectories[0] 191 else: 192 return self.selectDeviceDirectory(deviceDirectories) 193 else: 194 # return the default workspace and give the user a warning (unless 195 # silent mode is selected) 196 if not silent: 197 E5MessageBox.warning( 198 self.microPython, 199 self.tr("Workspace Directory"), 200 self.tr("Python files for this generic board can be" 201 " edited in place, if the device volume is locally" 202 " available. A volume named '{0}' was not found." 203 " In place editing will not be available." 204 ).format(self.__deviceVolumeName) 205 ) 206 207 return super().getWorkspace() 208