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