eric6/MicroPython/CircuitPythonDevices.py

branch
micropython
changeset 7059
a8fad276cbd5
child 7065
e3d04faced34
diff -r bdd583f96e96 -r a8fad276cbd5 eric6/MicroPython/CircuitPythonDevices.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/MicroPython/CircuitPythonDevices.py	Wed Jul 10 20:21:57 2019 +0200
@@ -0,0 +1,165 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2019 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the device interface class for CircuitPython boards.
+"""
+
+from __future__ import unicode_literals
+
+import os
+import ctypes
+from subprocess import check_output
+
+from E5Gui import E5MessageBox
+
+from .MicroPythonDevices import MicroPythonDevice
+from .MicroPythonReplWidget import HAS_QTCHART
+
+import Globals
+
+
+class CircuitPythonDevice(MicroPythonDevice):
+    """
+    Class implementing the device for CircuitPython boards.
+    """
+    def __init__(self, microPythonWidget, parent=None):
+        """
+        Constructor
+        
+        @param microPythonWidget reference to the main MicroPython widget
+        @type MicroPythonReplWidget
+        @param parent reference to the parent object
+        @type QObject
+        """
+        super(CircuitPythonDevice, self).__init__(microPythonWidget, parent)
+        
+        self.__replActive = False
+        self.__plotterActive = False
+    
+    def setButtons(self):
+        """
+        Public method to enable the supported action buttons.
+        """
+        super(CircuitPythonDevice, self).setButtons()
+        self.microPython.setActionButtons(repl=True, chart=HAS_QTCHART)
+    
+    def forceInterrupt(self):
+        """
+        Public method to determine the need for an interrupt when opening the
+        serial connection.
+        
+        @return flag indicating an interrupt is needed
+        @rtype bool
+        """
+        return False
+    
+    def canStartRepl(self):
+        """
+        Public method to determine, if a REPL can be started.
+        
+        @return tuple containing a flag indicating it is safe to start a REPL
+            and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+    
+    def setRepl(self, on):
+        """
+        Public method to set the REPL status and dependent status.
+        
+        @param on flag indicating the active status
+        @type bool
+        """
+        self.__replActive = on
+    
+    def canStartPlotter(self):
+        """
+        Public method to determine, if a Plotter can be started.
+        
+        @return tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+    
+    def setPlotter(self, on):
+        """
+        Public method to set the Plotter status and dependent status.
+        
+        @param on flag indicating the active status
+        @type bool
+        """
+        self.__plotterActive = on
+    
+    def getWorkspace(self):
+        """
+        Public method to get the workspace directory.
+        
+        @return workspace directory used for saving files
+        @rtype str
+        """
+        deviceDirectory = None
+        
+        # Attempts to find the path on the filesystem that represents the
+        # plugged in CIRCUITPY board.
+        if Globals.isWindowsPlatform():
+            # we are on a Windows platform
+            def getVolumeName(diskName):
+                """
+                Local function to determine the volume of a disk or device.
+                
+                Each disk or external device connected to windows has an
+                attribute called "volume name". This function returns the
+                volume name for the given disk/device.
+
+                Code from http://stackoverflow.com/a/12056414
+                """
+                volumeNameBuffer = ctypes.create_unicode_buffer(1024)
+                ctypes.windll.kernel32.GetVolumeInformationW(
+                    ctypes.c_wchar_p(diskName), volumeNameBuffer,
+                    ctypes.sizeof(volumeNameBuffer), None, None, None, None, 0)
+                return volumeNameBuffer.value
+            
+            #
+            # In certain circumstances, volumes are allocated to USB
+            # storage devices which cause a Windows popup to raise if their
+            # volume contains no media. Wrapping the check in SetErrorMode
+            # with SEM_FAILCRITICALERRORS (1) prevents this popup.
+            #
+            oldMode = ctypes.windll.kernel32.SetErrorMode(1)
+            try:
+                for disk in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
+                    path = '{}:\\'.format(disk)
+                    if (os.path.exists(path) and
+                            getVolumeName(path) == 'CIRCUITPY'):
+                        return path
+            finally:
+                ctypes.windll.kernel32.SetErrorMode(oldMode)
+        else:
+            # we are on a Linux or macOS platform
+            for mountCommand in ['mount', '/sbin/mount']:
+                try:
+                    mountOutput = check_output(mountCommand).splitlines()
+                    mountedVolumes = [x.split()[2] for x in mountOutput]
+                    for volume in mountedVolumes:
+                        if volume.endswith(b'CIRCUITPY'):
+                            deviceDirectory = volume.decode('utf-8')
+                except FileNotFoundError:
+                    next
+        
+        if deviceDirectory:
+            return deviceDirectory
+        else:
+            # return the default workspace and give the user a warning
+            E5MessageBox.warning(
+                self.microPythonWidget,
+                self.tr("Workspace Directory"),
+                self.tr("Python files for CircuitPython devices are stored on"
+                        " the device. Therefore, to edit these files you need"
+                        " to have the device plugged in. Until you plug in a"
+                        " device, the standard directory will be used."))
+            
+            return super(CircuitPythonDevice, self).getWorkspace()

eric ide

mercurial