eric6/MicroPython/CircuitPythonDevices.py

branch
micropython
changeset 7100
c4d9c28ebcd8
parent 7092
7414b3b012b1
child 7116
233b6e62ca2b
equal deleted inserted replaced
7099:89f11ae6bec3 7100:c4d9c28ebcd8
7 Module implementing the device interface class for CircuitPython boards. 7 Module implementing the device interface class for CircuitPython boards.
8 """ 8 """
9 9
10 from __future__ import unicode_literals 10 from __future__ import unicode_literals
11 11
12 import os
13 import ctypes
14 from subprocess import check_output
15
16 from E5Gui import E5MessageBox 12 from E5Gui import E5MessageBox
17 13
18 from .MicroPythonDevices import MicroPythonDevice 14 from .MicroPythonDevices import MicroPythonDevice
19 from .MicroPythonReplWidget import HAS_QTCHART 15 from .MicroPythonReplWidget import HAS_QTCHART
20 16
21 import Globals 17 import Utilities
22 18
23 19
24 class CircuitPythonDevice(MicroPythonDevice): 20 class CircuitPythonDevice(MicroPythonDevice):
25 """ 21 """
26 Class implementing the device for CircuitPython boards. 22 Class implementing the device for CircuitPython boards.
33 @type MicroPythonReplWidget 29 @type MicroPythonReplWidget
34 @param parent reference to the parent object 30 @param parent reference to the parent object
35 @type QObject 31 @type QObject
36 """ 32 """
37 super(CircuitPythonDevice, self).__init__(microPythonWidget, parent) 33 super(CircuitPythonDevice, self).__init__(microPythonWidget, parent)
38
39 self.__replActive = False
40 self.__plotterActive = False
41 34
42 def setButtons(self): 35 def setButtons(self):
43 """ 36 """
44 Public method to enable the supported action buttons. 37 Public method to enable the supported action buttons.
45 """ 38 """
46 super(CircuitPythonDevice, self).setButtons() 39 super(CircuitPythonDevice, self).setButtons()
47 self.microPython.setActionButtons(run=True, repl=True, chart=HAS_QTCHART) 40 ## self.microPython.setActionButtons(
41 ## run=True, repl=True, chart=HAS_QTCHART)
42 # TODO: check, if this really works
43 self.microPython.setActionButtons(
44 run=True, repl=True, files=True, chart=HAS_QTCHART)
48 45
49 workspace = self.getWorkspace() 46 workspace = self.getWorkspace()
50 if workspace.endswith("CIRCUITPY"): 47 if workspace.endswith("CIRCUITPY"):
51 self.microPython.setActionButtons(open=True, save=True) 48 self.microPython.setActionButtons(open=True, save=True)
52 49
68 and a reason why it cannot. 65 and a reason why it cannot.
69 @rtype tuple of (bool, str) 66 @rtype tuple of (bool, str)
70 """ 67 """
71 return True, "" 68 return True, ""
72 69
73 def setRepl(self, on):
74 """
75 Public method to set the REPL status and dependent status.
76
77 @param on flag indicating the active status
78 @type bool
79 """
80 self.__replActive = on
81
82 def canStartPlotter(self): 70 def canStartPlotter(self):
83 """ 71 """
84 Public method to determine, if a Plotter can be started. 72 Public method to determine, if a Plotter can be started.
85 73
86 @return tuple containing a flag indicating it is safe to start a 74 @return tuple containing a flag indicating it is safe to start a
87 Plotter and a reason why it cannot. 75 Plotter and a reason why it cannot.
88 @rtype tuple of (bool, str) 76 @rtype tuple of (bool, str)
89 """ 77 """
90 return True, "" 78 return True, ""
91
92 def setPlotter(self, on):
93 """
94 Public method to set the Plotter status and dependent status.
95
96 @param on flag indicating the active status
97 @type bool
98 """
99 self.__plotterActive = on
100 79
101 def canRunScript(self): 80 def canRunScript(self):
102 """ 81 """
103 Public method to determine, if a script can be executed. 82 Public method to determine, if a script can be executed.
104 83
116 @type str 95 @type str
117 """ 96 """
118 pythonScript = script.split("\n") 97 pythonScript = script.split("\n")
119 self.sendCommands(pythonScript) 98 self.sendCommands(pythonScript)
120 99
100 # TODO: check, if this really works
101 def canStartFileManager(self):
102 """
103 Public method to determine, if a File Manager can be started.
104
105 @return tuple containing a flag indicating it is safe to start a
106 File Manager and a reason why it cannot.
107 @rtype tuple of (bool, str)
108 """
109 return True, ""
110
121 def getWorkspace(self): 111 def getWorkspace(self):
122 """ 112 """
123 Public method to get the workspace directory. 113 Public method to get the workspace directory.
124 114
125 @return workspace directory used for saving files 115 @return workspace directory used for saving files
126 @rtype str 116 @rtype str
127 """ 117 """
128 deviceDirectory = None
129
130 # Attempts to find the path on the filesystem that represents the 118 # Attempts to find the path on the filesystem that represents the
131 # plugged in CIRCUITPY board. 119 # plugged in CIRCUITPY board.
132 if Globals.isWindowsPlatform(): 120 deviceDirectory = Utilities.findVolume("CIRCUITPY")
133 # we are on a Windows platform
134 def getVolumeName(diskName):
135 """
136 Local function to determine the volume of a disk or device.
137
138 Each disk or external device connected to windows has an
139 attribute called "volume name". This function returns the
140 volume name for the given disk/device.
141
142 Code from http://stackoverflow.com/a/12056414
143 """
144 volumeNameBuffer = ctypes.create_unicode_buffer(1024)
145 ctypes.windll.kernel32.GetVolumeInformationW(
146 ctypes.c_wchar_p(diskName), volumeNameBuffer,
147 ctypes.sizeof(volumeNameBuffer), None, None, None, None, 0)
148 return volumeNameBuffer.value
149
150 #
151 # In certain circumstances, volumes are allocated to USB
152 # storage devices which cause a Windows popup to raise if their
153 # volume contains no media. Wrapping the check in SetErrorMode
154 # with SEM_FAILCRITICALERRORS (1) prevents this popup.
155 #
156 oldMode = ctypes.windll.kernel32.SetErrorMode(1)
157 try:
158 for disk in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
159 path = "{0}:\\".format(disk)
160 if (os.path.exists(path) and
161 getVolumeName(path) == "CIRCUITPY"):
162 deviceDirectory = path
163 break
164 finally:
165 ctypes.windll.kernel32.SetErrorMode(oldMode)
166 else:
167 # we are on a Linux or macOS platform
168 for mountCommand in ["mount", "/sbin/mount", "/usr/sbin/mount"]:
169 try:
170 mountOutput = check_output(mountCommand).splitlines()
171 mountedVolumes = [x.split()[2] for x in mountOutput]
172 for volume in mountedVolumes:
173 if volume.endswith(b"CIRCUITPY"):
174 deviceDirectory = volume.decode("utf-8")
175 break
176 if deviceDirectory:
177 break
178 except FileNotFoundError:
179 pass
180 121
181 if deviceDirectory: 122 if deviceDirectory:
182 return deviceDirectory 123 return deviceDirectory
183 else: 124 else:
184 # return the default workspace and give the user a warning 125 # return the default workspace and give the user a warning

eric ide

mercurial