[
  {
    "path": ".github/workflows/create_executables.yml",
    "content": "name: Package Application with Pyinstaller\n\non:\n  push:\n    tags:\n      - \"v*.*.*\"\n\njobs:\n\n  build_windows:\n    runs-on: windows-latest\n    steps:\n      - name: Create Executable\n        uses: sayyid5416/pyinstaller@v1\n        with:\n          spec: 'simpleFOCStudio.spec'\n          requirements: 'requirements.txt'\n          python_ver: '3.9'\n          python_arch: 'x64'\n          exe_path: './dist/windows'\n\n      - name: Rename file with details\n        run: mv dist/windows/simpleFOCStudio.exe dist/windows/simpleFOCStudio-windows-x86_64-${{ github.ref_name }}.exe\n      \n      - name: Release\n        uses: softprops/action-gh-release@v1\n        with:\n          files: |\n            dist/windows/**\n\n  build_linux:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Install pyqt5 dependencies\n        run: sudo apt install -y qtbase5-dev\n      - name: Create Executable\n        uses: sayyid5416/pyinstaller@v1\n        with:\n          spec: 'simpleFOCStudio.spec'\n          requirements: 'requirements.txt'\n          python_ver: '3.9'\n          python_arch: 'x64'\n          exe_path: './dist/linux'\n\n      - name: Rename file with details\n        run: mv dist/linux/simpleFOCStudio dist/linux/simpleFOCStudio-linux-x86_64-${{ github.ref_name }}\n      \n      - name: Release\n        uses: softprops/action-gh-release@v1\n        with:\n          files: |\n            dist/linux/**\n"
  },
  {
    "path": ".gitignore",
    "content": "/venv\n/.idea\n**/*.log\n**/__pycache__\n\nbuild/\ndist/"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 JorgeMaker\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "## *Simple**FOC**Studio*\n\nGraphical user interface for the [*Simple**FOC**library*](https://github.com/simplefoc). This application allows to tune and configure any BLDC/Stepper *Simple**FOC**library* controlled device, using serial port communications and the [Commander](https://docs.simplefoc.com/commander_interface) interface.\n#### The main features are:\n\n- Plug and play with the *Simple**FOC**library* version 2.1\n- Real-time tuning and configuration of the motors\n- Real-time plotting and monitoring of motor variables\n- Code generation for easier integration of the tuned parameters in your code\n- Built on PyQt5 and a standardized `SimpleFOCConnector` interface that can be used as a gateway form python to the *Simple**FOC**library* device.\n\n<p align=\"center\">\n  <img  src=\"./DOC/new_gif.gif\">\n</p>\n\n### Installation\nDon't worry, *Simple**FOC**Studio* is easy to install even if you have never used the terminal before! 😃\nThere are just couple of steps to take:\n1. Install Python if you don't have it installed yet\n    - We suggest to use Anaconda. [Here is how to install it.](https://docs.anaconda.com/anaconda/install/)\n    - Once you have your Anaconda running open your terminal (on windows anaconda prompt) and run:\n    ```sh\n    conda create -n simplefoc python=3.9.0\n    ```\n    - Once this is done you will never have to run that command again, from now on you will just need:\n    ```sh\n    conda activate simplefoc\n    ```\n2. Clone this repository or download the zip file\n3. Enter the folder containing the repository using the terminal\n    -  the command will be something like this:\n    ```sh\n    cd  some_path_on_disk/SimpleFOCStudio\n    ```\n4. Final step of the installation is installing all the necessary libraries for the *Simple**FOC**Studio* :\n    ```sh\n    pip install -r \"requirements.txt\"\n    ```\n\nOnce you have done all the steps above you do not need to repeat them any more. All you need to do the next time is open your terminal in the *Simple**FOC**Studio* directory and run the command:\n```sh\npython simpleFOCStudio.py\n```\nOr if using Anaconda:\n```sh   \nconda activate simplefoc\npython simpleFOCStudio.py\n```\n\n\n### Usage\n*Simple**FOC**Studio* has several useful features:\n- A simple approach to tuning your motor setup\n  - Form view for fast motion control PID/LPF tuning\n  - TreeView for more in depth tunning and experimenting\n- Code generation for transferring the found parameters into your arduino code\n- Serial terminal integrated with various commander features\n#### Motion control tunning windows\n\n\nOnce you have your application running add a device by clicking the  <img src=\"./src/gui/resources/add_motor.png\" height=\"18\"> motor button in the toolbar. You can choose either the <img src=\"./src/gui/resources/tree.png\" height=\"18\"> TreeView or the <img src=\"./src/gui/resources/form.png\" height=\"18\">FormView.\n- To connect to your device first configure the serial port by clicking on <img src=\"./src/gui/resources/configure.png\" height=\"18\">Configure button\n- Add your com port info and click OK\n- Then add the device command ID that you've added to the commander usually its `M`\n   - Command `M` , Arduino code : `command.add('M',doMotor,\"my motor\")`\n   - Command `A` , Arduino code : `command.add('A',doMotor,\"my motor\")`\n- Then click to the <img src=\"./src/gui/resources/connect.png\" height=\"18\">Connect button and you should be ready to go!\n\n<p align=\"center\">\n  <img src=\"./DOC/treeview.png\" width=\"400px\">\n  <img src=\"./DOC/formview.png\" width=\"400px\">\n</p>\n\n#### Code generation\n\n*Simple**FOC**Studio* helps you to easier transfer your carefully tuned parameters to the Arduino code. Once you are happy with the performance of your system you can automatically generate the arduino code of the parameters you have tuned. To generate the code :\n- Click on the <img src=\"./src/gui/resources/gen.png\" height=\"18\"> Arudino button in the toolbar.\n- Choose which sets of parameters you wish to generate the code for and click OK\n- In the new tab you will have a code of your tuned parameters.\n\nThe generated code you can just copy/paste in your <code>setup()</code> function, just before calling the <code>motor.init()</code>\n\n<p align=\"center\">\n  <img src=\"./DOC/gen.gif\" width=\"700px\">\n</p>\n\n#### Custom Commands\n\nYou can create your own custom commands if you [extend the Commnader interface](https://docs.simplefoc.com/commander_interface) in your sketch. This can be used for example to do things like change register settings for SPI devicesor any oyher functionality. Each custom command has a name and a value as you can see at the below image.\n\n<p align=\"center\">\n  <img src=\"./DOC/customCommands.png\">\n</p>\nOnce you have added each custom command in order to execute it you just need to select it and once selected press the space key (⎵) or right arrow key (→).\n\n#### Jogging panel\n<p align=\"center\">\n  <img src=\"./DOC/JoggingPanel.png\">\n</p>\nThis panel is used to actuate with yor motor without having to write comands, is like using a joystick but pressing buttons. Each buton performas an action:\n\n- Fast Reverse button: reduces the current target by 2 times the specified increment.\n- Reverse button: reduces the current target by the specified increment.\n- Fordward button: Increase the current target by the specified increment.\n- Fast Fordward button: Increase the current target by 2 times the specified increment.\n- Stop button: in angle control mode, sets the current angle as target angle and in velocity control sets the target to zero.\n\n\n#### Integrated serial terminal\n\n*Simple**FOC**Studio* also has integrated serial terminal for easier debugging and monitoring.\n\n<p align=\"center\">\n  <img src=\"./DOC/term.png\" width=\"700px\">\n</p>\n\n### Arduino code\n\nBasically there are two things you need to do:\n1. Use the commander interface and add the motor to the commander\n2. Use the monitoring and add the `motor.monitor()` in the loop\n\nHere is a mockup of the code:\n\n```cpp\n#include <SimpleFOC.h>\n\n....\n\n// include commander interface\nCommander command = Commander(Serial);\nvoid doMotor(char* cmd) { command.motor(&motor, cmd); }\n\nvoid setup(){\n  ....\n  // add the motor to the commander interface\n  // The letter (here 'M') you will provide to the SimpleFOCStudio\n  command.add('M',doMotor,\"motor\");\n  // tell the motor to use the monitoring\n  motor.useMonitoring(Serial);\n  motor.monitor_downsample = 0; // disable monitor at first - optional\n  ...\n\n}\nvoid loop(){\n  ....\n\n  ....\n  // real-time monitoring calls\n  motor.monitor();\n  // real-time commander calls\n  command.run();\n}\n```\n"
  },
  {
    "path": "command_to_generate_spec.txt",
    "content": "pyi-makespec --onefile --noconsole --icon src/gui/resources/studioicon.icns --add-data src:src simpleFOCStudio.py\n"
  },
  {
    "path": "device.json",
    "content": "{\n    \"LPFAngle\": 0.0,\n    \"LPFCurrentD\": 0.005,\n    \"LPFCurrentQ\": 0.005,\n    \"LPFVelocity\": 0.2,\n    \"PIDAngle\": {\n        \"D\": 0.0,\n        \"I\": 0.0,\n        \"P\": 20.0,\n        \"outputLimit\": 10.0,\n        \"outputRamp\": 0.0\n    },\n    \"PIDCurrentD\": {\n        \"D\": 0.0,\n        \"I\": 300.0,\n        \"P\": 3.0,\n        \"outputLimit\": 12.0,\n        \"outputRamp\": 0.0\n    },\n    \"PIDCurrentQ\": {\n        \"D\": 0.0,\n        \"I\": 300.0,\n        \"P\": 3.0,\n        \"outputLimit\": 12.0,\n        \"outputRamp\": 0.0\n    },\n    \"PIDVelocity\": {\n        \"D\": 0.0,\n        \"I\": 20.0,\n        \"P\": 0.2,\n        \"outputLimit\": 11.0,\n        \"outputRamp\": 1000.0\n    },\n    \"connectionID\": \"\",\n    \"controlType\": 2,\n    \"currentLimit\": 0.2,\n    \"customCommands\": [\n        {\n            \"commandName\": \"Command1\",\n            \"commandValue\": \"D100\"\n        }\n    ],\n    \"devCommandID\": \"M\",\n    \"initialTarget\": 0,\n    \"motionDownsample\": 0.0,\n    \"phaseResistance\": 0.0,\n    \"sensorElectricalZero\": 2.676,\n    \"sensorZeroOffset\": 0.0,\n    \"serialByteSize\": 8,\n    \"serialParity\": \"N\",\n    \"serialPortName\": \"/dev/cu.usbserial-14140\",\n    \"serialRate\": \"115200\",\n    \"stopBits\": 1,\n    \"torqueType\": 0,\n    \"velocityLimit\": 10.0,\n    \"voltageLimit\": 11.0\n}"
  },
  {
    "path": "requirements.txt",
    "content": "# Requirements for SimpleFOCStudio\nPyQt5==5.15.9\npyqtgraph==0.13.1\npyserial==3.5\nnumpy==1.24.0\n# Requirements for Pyinstaller packaging process:\npyinstaller\nPillow"
  },
  {
    "path": "scriptTest.py",
    "content": "from src.simpleFOCConnector import SimpleFOCDevice\nimport time\nif __name__ == '__main__':\n    deviceConnector = SimpleFOCDevice.getInstance()\n    deviceConnector.serialPortName = 'COM32'\n    deviceConnector.serialRate = 115200\n    deviceConnector.devCommandID = 'M'\n\n    if deviceConnector.connect(SimpleFOCDevice.ONLY_CONNECT):\n        while True:\n            deviceConnector.sendControlType(SimpleFOCDevice.ANGLE_CONTROL)\n            deviceConnector.sendTargetValue(0)\n            time.sleep(2.0)\n            deviceConnector.sendTargetValue(3)\n            time.sleep(2)\n            deviceConnector.sendTargetValue(6)\n            time.sleep(2)\n            deviceConnector.sendTargetValue(-6)\n            time.sleep(2)\n            deviceConnector.sendControlType(SimpleFOCDevice.VELOCITY_CONTROL)\n            deviceConnector.sendTargetValue(30)\n            time.sleep(2)\n            deviceConnector.sendTargetValue(-30)\n            time.sleep(2)\n"
  },
  {
    "path": "simpleFOCStudio.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\" This module contains ans script to start the SimpleFOC ConfigTool, a GIU\n    application ta monitor, tune and configure BLDC motor controllers based on\n    SimpleFOC library.\n\"\"\"\nfrom PyQt5 import QtWidgets, QtCore\nfrom src.gui.mainWindow import UserInteractionMainWindow\nimport sys\nimport logging\n\nif __name__ == '__main__':\n    try:\n        QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True) \n        QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True)\n        logging.basicConfig(filename='.SimpleFOCConfigTool.log', filemode='w',\n                         format='%(name)s - %(levelname)s - %(message)s')\n        app = QtWidgets.QApplication(sys.argv)\n        mainWindow = QtWidgets.QMainWindow()\n        userInteractionMainWindow = UserInteractionMainWindow()\n        userInteractionMainWindow.setupUi(mainWindow)\n        mainWindow.show()\n        sys.exit(app.exec_())\n    except Exception as exception:\\\n    logging.error(exception, exc_info=True)\n"
  },
  {
    "path": "simpleFOCStudio.spec",
    "content": "# -*- mode: python ; coding: utf-8 -*-\n\n\na = Analysis(\n    ['simpleFOCStudio.py'],\n    pathex=[],\n    binaries=[],\n    datas=[('src', 'src')],\n    hiddenimports=[],\n    hookspath=[],\n    hooksconfig={},\n    runtime_hooks=[],\n    excludes=[],\n    noarchive=False,\n)\npyz = PYZ(a.pure)\n\nexe = EXE(\n    pyz,\n    a.scripts,\n    a.binaries,\n    a.datas,\n    [],\n    name='simpleFOCStudio',\n    debug=False,\n    bootloader_ignore_signals=False,\n    strip=False,\n    upx=True,\n    upx_exclude=[],\n    runtime_tmpdir=None,\n    console=False,\n    disable_windowed_traceback=False,\n    argv_emulation=False,\n    target_arch=None,\n    codesign_identity=None,\n    entitlements_file=None,\n    icon=['src\\\\gui\\\\resources\\\\studioicon.icns'],\n)\n"
  },
  {
    "path": "src/gui/commandlinetool/commandlinetool.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom PyQt5 import QtWidgets\n\nfrom src.gui.commandlinetool.configureConnectionWidget import \\\n    ConfigureConnection\nfrom src.gui.sharedcomnponets.commandLineInterface import CommandLineWidget\nfrom src.gui.sharedcomnponets.sharedcomponets import (WorkAreaTabWidget,\n                                                      GUIToolKit)\nfrom src.simpleFOCConnector import SimpleFOCDevice\n\n\nclass CommandLineConsoleTool(WorkAreaTabWidget):\n\n    def __init__(self, parent=None):\n        super().__init__(parent)\n\n        self.device = SimpleFOCDevice.getInstance()\n\n        self.verticalLayout = QtWidgets.QVBoxLayout(self)\n        self.verticalLayout.setObjectName('verticalLayout')\n\n        self.configureConnection = ConfigureConnection()\n        self.verticalLayout.addWidget(self.configureConnection)\n\n        self.commandLineInterface = CommandLineWidget()\n        self.verticalLayout.addWidget(self.commandLineInterface)\n\n        self.device.commProvider.rawDataReceived.connect(self.commandLineInterface.publishCommandResponseData)\n\n    def getTabIcon(self):\n        return GUIToolKit.getIconByName('consoletool')\n\n    def getTabName(self):\n        return self.device.connectionID\n"
  },
  {
    "path": "src/gui/commandlinetool/configureConnectionWidget.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nimport serial\nfrom PyQt5 import (QtGui, QtCore, QtWidgets)\n\nfrom src.gui.sharedcomnponets.sharedcomponets import GUIToolKit\nfrom src.gui.sharedcomnponets.sharedcomponets import SerialPortComboBox\nfrom src.simpleFOCConnector import SimpleFOCDevice\n\n\nclass ConfigureConnection(QtWidgets.QGroupBox):\n\n    def __init__(self, parent=None):\n        super().__init__(parent)\n\n        self.device = SimpleFOCDevice.getInstance()\n\n        self.setTitle('Configure serial connection')\n        self.setObjectName('configureConnection')\n\n        self.configCoonLayout = QtWidgets.QHBoxLayout(self)\n        self.configCoonLayout.setObjectName(\n            'configureConnectionorizontalLayout')\n\n        self.portNameLabel = QtWidgets.QLabel(self)\n        self.portNameLabel.setObjectName('portNameLabel')\n        self.configCoonLayout.addWidget(self.portNameLabel)\n\n        self.portNameComboBox = SerialPortComboBox(self)\n        self.portNameComboBox.setObjectName('portNameComboBox')\n        self.portNameComboBox.setMinimumWidth(250)\n        self.configCoonLayout.addWidget(self.portNameComboBox)\n\n        self.bitRateLabel = QtWidgets.QLabel(self)\n        self.bitRateLabel.setObjectName('bitRateLabel')\n        self.configCoonLayout.addWidget(self.bitRateLabel)\n\n        self.bitRatelineEdit = QtWidgets.QLineEdit(self)\n        self.bitRatelineEdit.setObjectName('bitRatelineEdit')\n        self.bitRatelineEdit.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp(\"^[0-9]*$\")))\n        self.bitRatelineEdit.setText('115200')\n        self.configCoonLayout.addWidget(self.bitRatelineEdit)\n\n        self.parityLabel = QtWidgets.QLabel(self)\n        self.parityLabel.setObjectName('parityLabel')\n        self.configCoonLayout.addWidget(self.parityLabel)\n\n        self.parityComboBox = QtWidgets.QComboBox(self)\n        self.parityComboBox.setObjectName('parityComboBox')\n        self.parityComboBox.addItems(serial.PARITY_NAMES.values())\n        self.configCoonLayout.addWidget(self.parityComboBox)\n\n        serial.PARITY_NAMES.values()\n\n        self.byteSizeLabel = QtWidgets.QLabel(self)\n        self.byteSizeLabel.setObjectName('byteSizeLabel')\n        self.configCoonLayout.addWidget(self.byteSizeLabel)\n\n        self.byteSizeComboBox = QtWidgets.QComboBox(self)\n        self.byteSizeComboBox.setObjectName('byteSizeComboBox')\n        byteSizeList = [str(serial.EIGHTBITS), str(serial.FIVEBITS),\n                        str(serial.SIXBITS),\n                        str(serial.SEVENBITS)]\n        self.byteSizeComboBox.addItems(byteSizeList)\n        self.configCoonLayout.addWidget(self.byteSizeComboBox)\n\n        self.stopBitsLabel = QtWidgets.QLabel(self)\n        self.stopBitsLabel.setObjectName('stopBitsLabel')\n        self.configCoonLayout.addWidget(self.stopBitsLabel)\n\n        self.stopBitsComboBox = QtWidgets.QComboBox(self)\n        byteStopBitsList = [str(serial.STOPBITS_ONE),\n                            str(serial.STOPBITS_ONE_POINT_FIVE),\n                            str(serial.STOPBITS_TWO)]\n        self.stopBitsComboBox.addItems(byteStopBitsList)\n        self.stopBitsComboBox.setObjectName('stopBitsComboBox')\n        self.configCoonLayout.addWidget(self.stopBitsComboBox)\n\n        self.connectDisconnectButton = QtWidgets.QPushButton(self)\n        self.connectDisconnectButton.setIcon(\n            GUIToolKit.getIconByName('connect'))\n        self.connectDisconnectButton.setObjectName('connectDeviceButton')\n        self.connectDisconnectButton.setText('Connect')\n        self.connectDisconnectButton.clicked.connect(\n            self.connectDisconnectDeviceAction)\n\n        self.configCoonLayout.addWidget(self.connectDisconnectButton)\n\n        self.portNameLabel.setText('Port Name')\n        self.bitRateLabel.setText('Bit rate')\n        self.parityLabel.setText('Parity')\n        self.byteSizeLabel.setText('Byte size')\n        self.stopBitsLabel.setText('Stop bits')\n\n        self.device.addConnectionStateListener(self)\n        self.connectionStateChanged(self.device.isConnected)\n\n    def getConfigValues(self):\n        values = {\n            'connectionID': '',\n            'serialPortName': self.portNameComboBox.currentText(),\n            'serialRate': self.bitRatelineEdit.text(),\n            'stopBits': self.stopBitsExtractor(self.stopBitsComboBox.currentText()),\n            'serialByteSize': int(str(self.byteSizeComboBox.currentText())),\n            'serialParity':  list(serial.PARITY_NAMES.keys())[list(serial.PARITY_NAMES.values()).index(self.parityComboBox.currentText())][0]\n        }\n        return values\n\n    def stopBitsExtractor(self, value):\n        if value == '1.5':\n            return float(self.stopBitsComboBox.currentText())\n        else:\n            return int(self.stopBitsComboBox.currentText())\n\n    def connectionStateChanged(self, isConnectedFlag):\n        if isConnectedFlag:\n            self.connectDisconnectButton.setText('Disconnect')\n            self.connectDisconnectButton.setIcon(\n                GUIToolKit.getIconByName('disconnect'))\n        else:\n            self.connectDisconnectButton.setText('Connect')\n            self.connectDisconnectButton.setIcon(\n                GUIToolKit.getIconByName('connect'))\n\n        self.portNameLabel.setEnabled(not isConnectedFlag)\n        self.portNameComboBox.setEnabled(not isConnectedFlag)\n        self.bitRateLabel.setEnabled(not isConnectedFlag)\n        self.bitRatelineEdit.setEnabled(not isConnectedFlag)\n        self.parityLabel.setEnabled(not isConnectedFlag)\n        self.parityComboBox.setEnabled(not isConnectedFlag)\n        self.byteSizeLabel.setEnabled(not isConnectedFlag)\n        self.byteSizeComboBox.setEnabled(not isConnectedFlag)\n        self.stopBitsLabel.setEnabled(not isConnectedFlag)\n        self.stopBitsComboBox.setEnabled(not isConnectedFlag)\n\n    def connectDisconnectDeviceAction(self):\n        if self.device.isConnected:\n            self.disConnectAction()\n        else:\n            self.connectAction()\n\n    def connectAction(self):\n        deviceConfig = self.getConfigValues()\n        self.device.configureConnection(deviceConfig)\n        self.device.connect(SimpleFOCDevice.ONLY_CONNECT)\n\n    def disConnectAction(self):\n        self.device.disConnect()"
  },
  {
    "path": "src/gui/configtool/configureConnectionDialog.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nimport serial\nfrom PyQt5 import (QtCore, QtGui, QtWidgets)\n\nfrom src.gui.sharedcomnponets.sharedcomponets import SerialPortComboBox\nfrom src.simpleFOCConnector import SimpleFOCDevice\n\n\nclass ConfigureSerailConnectionDialog(QtWidgets.QDialog):\n    def __init__(self, parent=None):\n        super().__init__(parent)\n\n        self.setupUi(SimpleFOCDevice.getInstance())\n\n    def setupUi(self, device=None):\n        self.setObjectName('Dialog')\n        self.resize(700, 188)\n\n        self.gridLayout = QtWidgets.QGridLayout(self)\n        self.gridLayout.setObjectName('gridLayout')\n\n        self.portNameLabel = QtWidgets.QLabel(self)\n        self.portNameLabel.setObjectName('portNameLabel')\n        self.gridLayout.addWidget(self.portNameLabel, 0, 0, 1, 1)\n\n        self.portNameComboBox = SerialPortComboBox(self)\n        self.portNameComboBox.setObjectName('portNameComboBox')\n        self.portNameComboBox.setMinimumWidth(250)\n        self.gridLayout.addWidget(self.portNameComboBox, 0, 1, 1, 1)\n\n        self.bitRateLabel = QtWidgets.QLabel(self)\n        self.bitRateLabel.setObjectName('bitRateLabel')\n        self.gridLayout.addWidget(self.bitRateLabel, 0, 2, 1, 1)\n\n\n\n        self.bitRatelineEdit = QtWidgets.QLineEdit(self)\n        self.bitRatelineEdit.setObjectName('bitRatelineEdit')\n        self.bitRatelineEdit.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp(\"^[0-9]*$\")))\n        self.gridLayout.addWidget(self.bitRatelineEdit, 0, 3, 1, 1)\n\n        self.parityLabel = QtWidgets.QLabel(self)\n        self.parityLabel.setObjectName('parityLabel')\n        self.gridLayout.addWidget(self.parityLabel, 1, 0, 1, 1)\n\n        self.parityComboBox = QtWidgets.QComboBox(self)\n        self.parityComboBox.setObjectName('parityComboBox')\n        self.parityComboBox.addItems(serial.PARITY_NAMES.values())\n        self.gridLayout.addWidget(self.parityComboBox, 1, 1, 1, 1)\n\n        serial.PARITY_NAMES.values()\n\n        self.byteSizeLabel = QtWidgets.QLabel(self)\n        self.byteSizeLabel.setObjectName('byteSizeLabel')\n        self.gridLayout.addWidget(self.byteSizeLabel, 1, 2, 1, 1)\n\n        self.byteSizeComboBox = QtWidgets.QComboBox(self)\n        self.byteSizeComboBox.setObjectName('byteSizeComboBox')\n        byteSizeList = [str(serial.EIGHTBITS), str(serial.FIVEBITS), str(serial.SIXBITS),\n                        str(serial.SEVENBITS)]\n        self.byteSizeComboBox.addItems(byteSizeList)\n        self.gridLayout.addWidget(self.byteSizeComboBox, 1, 3, 1, 1)\n\n        self.stopBitsLabel = QtWidgets.QLabel(self)\n        self.stopBitsLabel.setObjectName('stopBitsLabel')\n        self.gridLayout.addWidget(self.stopBitsLabel, 2, 0, 1, 1)\n\n        self.stopBitsComboBox = QtWidgets.QComboBox(self)\n        byteStopBitsList = [str(serial.STOPBITS_ONE),\n                            str(serial.STOPBITS_ONE_POINT_FIVE),\n                            str(serial.STOPBITS_TWO)]\n        self.stopBitsComboBox.addItems(byteStopBitsList)\n        self.stopBitsComboBox.setObjectName('stopBitsComboBox')\n        self.gridLayout.addWidget(self.stopBitsComboBox, 2, 1, 1, 1)\n\n        self.connectionIDLabel = QtWidgets.QLabel(self)\n        self.connectionIDLabel.setObjectName('connectionNameLabel')\n        self.gridLayout.addWidget(self.connectionIDLabel, 2, 2, 1, 1)\n\n        self.connectionIDlineEdit = QtWidgets.QLineEdit(self)\n        self.connectionIDlineEdit.setMaxLength(10)\n        self.connectionIDlineEdit.setObjectName('connectionNameEdit')\n        self.gridLayout.addWidget(self.connectionIDlineEdit, 2, 3, 1, 1)\n\n        self.buttonBox = QtWidgets.QDialogButtonBox(self)\n        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)\n        self.buttonBox.setStandardButtons(\n            QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok)\n        self.buttonBox.setObjectName('buttonBox')\n\n        self.gridLayout.addWidget(self.buttonBox, 3, 0, 1, 4)\n\n        self.setWindowTitle('Configure serial connection')\n        self.portNameLabel.setText('Port Name')\n        self.bitRateLabel.setText('Bit rate')\n        self.parityLabel.setText('Parity')\n        self.byteSizeLabel.setText('Byte size')\n        self.stopBitsLabel.setText('Stop bits')\n        self.connectionIDLabel.setText('Conn ID')\n\n        self.buttonBox.accepted.connect(self.accept)\n        self.buttonBox.rejected.connect(self.reject)\n\n        QtCore.QMetaObject.connectSlotsByName(self)\n\n        if device is not None:\n            self.fillForm(device)\n\n    def fillForm(self, deviceConnector):\n        self.connectionIDlineEdit.setText(deviceConnector.connectionID)\n        self.portNameComboBox.setCurrentText(deviceConnector.serialPortName)\n        self.bitRatelineEdit.setText(str(deviceConnector.serialRate))\n        self.stopBitsComboBox.setCurrentText(str(deviceConnector.stopBits))\n        self.byteSizeComboBox.setCurrentText(str(deviceConnector.serialByteSize))\n        self.parityComboBox.setCurrentText(str(deviceConnector.serialParity))\n\n    def getConfigValues(self):\n        values = {\n            'connectionID': self.connectionIDlineEdit.text(),\n            'serialPortName': self.portNameComboBox.currentText(),\n            'serialRate': self.bitRatelineEdit.text(),\n            'stopBits': self.stopBitsExtractor(self.stopBitsComboBox.currentText()),\n            'serialByteSize': int(str(self.byteSizeComboBox.currentText())),\n            'serialParity':  list(serial.PARITY_NAMES.keys())[list(serial.PARITY_NAMES.values()).index(self.parityComboBox.currentText())][0]\n        }\n        return values\n\n    def stopBitsExtractor(self, value):\n        if value == '1.5':\n            return float(self.stopBitsComboBox.currentText())\n        else:\n            return int(self.stopBitsComboBox.currentText())"
  },
  {
    "path": "src/gui/configtool/connectionControl.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom PyQt5 import QtWidgets\n\nfrom src.gui.configtool.configureConnectionDialog import \\\n    ConfigureSerailConnectionDialog\nfrom src.gui.sharedcomnponets.sharedcomponets import GUIToolKit\nfrom src.simpleFOCConnector import SimpleFOCDevice\n\n\nclass ConnectionControlGroupBox(QtWidgets.QGroupBox):\n\n    def __init__(self, parent=None):\n        super().__init__(parent)\n\n        self.device = SimpleFOCDevice.getInstance()\n\n        self.setObjectName('connectionControl')\n        self.setTitle('Connection control')\n\n        self.horizontalLayout = QtWidgets.QHBoxLayout(self)\n        self.horizontalLayout.setObjectName('generalControlHL')\n\n        self.devCommandIDLabel = QtWidgets.QLabel(\"Command:\")\n        self.horizontalLayout.addWidget(self.devCommandIDLabel)\n\n        self.devCommandIDLetter = QtWidgets.QLineEdit()\n        self.devCommandIDLetter.setObjectName('devCommandIDLetter')\n        self.devCommandIDLetter.editingFinished.connect(self.changeDevicedevCommandID)\n        self.horizontalLayout.addWidget(self.devCommandIDLetter)\n        self.devCommandIDLetter.setText(self.device.devCommandID)\n\n        self.pullConfig = QtWidgets.QPushButton()\n        self.pullConfig.setObjectName('pullConfig')\n        self.pullConfig.setIcon(GUIToolKit.getIconByName('pull'))\n        self.pullConfig.setText(' Pull Params')\n        self.pullConfig.clicked.connect(self.device.pullConfiguration)\n        \n        self.horizontalLayout.addWidget(self.pullConfig)\n\n        self.connectDisconnectButton = QtWidgets.QPushButton(self)\n        self.connectDisconnectButton.setIcon(GUIToolKit.getIconByName('connect'))\n        self.connectDisconnectButton.setObjectName('connectDeviceButton')\n        self.connectDisconnectButton.setText('Connect')\n        self.connectDisconnectButton.clicked.connect(self.connectDisconnectDeviceAction)\n\n        self.horizontalLayout.addWidget(self.connectDisconnectButton)\n\n        self.configureDeviceButton = QtWidgets.QPushButton(self)\n        self.configureDeviceButton.setIcon(GUIToolKit.getIconByName('configure'))\n        self.configureDeviceButton.setObjectName('configureDeviceButton')\n        self.configureDeviceButton.setText('Configure')\n        self.configureDeviceButton.clicked.connect(self.configureDeviceAction)\n        self.horizontalLayout.addWidget(self.configureDeviceButton)\n\n        self.device.addConnectionStateListener(self)\n        self.connectionStateChanged(self.device.isConnected)\n    \n    def changeDevicedevCommandID(self):\n        self.device.devCommandID = self.devCommandIDLetter.text()\n\n    def connectDisconnectDeviceAction(self):\n        if self.device.isConnected:\n            self.device.disConnect()\n        else:\n            connectionMode  = SimpleFOCDevice.PULL_CONFIG_ON_CONNECT\n            self.device.connect(connectionMode)\n\n    def connectionStateChanged(self, isConnected):\n        if isConnected:\n            self.connectDisconnectButton.setIcon(\n                GUIToolKit.getIconByName('disconnect'))\n            self.connectDisconnectButton.setText('Disconnect')\n        else:\n            self.connectDisconnectButton.setIcon(\n                GUIToolKit.getIconByName('connect'))\n            self.connectDisconnectButton.setText('Connect')\n\n    def configureDeviceAction(self):\n        dialog = ConfigureSerailConnectionDialog()\n        result = dialog.exec_()\n        if result:\n            deviceConfig = dialog.getConfigValues()\n            self.device.configureConnection(deviceConfig)\n"
  },
  {
    "path": "src/gui/configtool/controlLoopConfig.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom PyQt5 import QtWidgets\n\nfrom src.simpleFOCConnector import SimpleFOCDevice\n\n\nclass ControlLoopGroupBox(QtWidgets.QGroupBox):\n    def __init__(self, parent=None):\n        super().__init__(parent)\n\n        self.device = SimpleFOCDevice.getInstance()\n\n        self.setObjectName('controlLoop')\n        self.setTitle('Control Loop Mode')\n\n        self.controlLoopHorizontalLayout = QtWidgets.QHBoxLayout(self)\n        self.controlLoopHorizontalLayout.setObjectName('controlLoopHorizontalLayout')\n\n        \n        self.selectorControlLoop = QtWidgets.QComboBox(self)\n        self.selectorControlLoop.setObjectName('selectorControlLoop')\n        self.selectorControlLoop.addItems(['Torque', 'Velocity', 'Angle', 'Velocity openloop', 'Angle openloop'])\n        self.selectorControlLoop.currentIndexChanged.connect(self.changeControlLoop)\n        self.controlLoopHorizontalLayout.addWidget(self.selectorControlLoop)\n\n        self.setControlLopMode(self.device.controlType)\n\n        self.disableUI()\n        self.device.addConnectionStateListener(self)\n        self.device.commProvider.commandDataReceived.connect(\n            self.commandResponseReceived)\n\n        self.connectionStateChanged(self.device.isConnected)\n\n    def connectionStateChanged(self, deviceConnected):\n        if deviceConnected is True:\n            self.enabeUI()\n        else:\n            self.disableUI()\n\n    def enabeUI(self):\n        self.setEnabled(True)\n\n    def disableUI(self):\n        self.setEnabled(False)\n\n    def setControlLopMode(self, value):\n        if value == SimpleFOCDevice.TORQUE_CONTROL:\n            self.selectorControlLoop.setCurrentIndex(0)\n        elif value == SimpleFOCDevice.VELOCITY_CONTROL:\n            self.selectorControlLoop.setCurrentIndex(1)\n        elif value == SimpleFOCDevice.ANGLE_CONTROL:\n            self.selectorControlLoop.setCurrentIndex(2)\n        elif value == SimpleFOCDevice.VELOCITY_OPENLOOP_CONTROL:\n            self.selectorControlLoop.setCurrentIndex(3)\n        elif value == SimpleFOCDevice.ANGLE_OPENLOOP_CONTROL:\n            self.selectorControlLoop.setCurrentIndex(4)\n\n    def changeControlLoop(self):\n        index = self.selectorControlLoop.currentIndex()\n        if index == 0:\n            self.device.sendControlType(SimpleFOCDevice.TORQUE_CONTROL)\n        elif index == 1:\n            self.device.sendControlType(SimpleFOCDevice.VELOCITY_CONTROL)\n        elif index == 2:\n            self.device.sendControlType(SimpleFOCDevice.ANGLE_CONTROL)\n        elif index == 3:\n            self.device.sendControlType(SimpleFOCDevice.VELOCITY_OPENLOOP_CONTROL)\n        elif index == 4:\n            self.device.sendControlType(SimpleFOCDevice.ANGLE_OPENLOOP_CONTROL)\n\n    def commandResponseReceived(self, cmdRespose):\n        self.setControlLopMode(self.device.controlType)"
  },
  {
    "path": "src/gui/configtool/deviceConfigurationTool.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom PyQt5 import QtWidgets\n\nfrom src.gui.configtool.connectionControl import ConnectionControlGroupBox\nfrom src.gui.configtool.controlLoopConfig import ControlLoopGroupBox\nfrom src.gui.configtool.deviceJoggingControl import DeviceJoggingControl\nfrom src.gui.configtool.droDisplayWidget import DROGroupBox\nfrom src.gui.configtool.generalControls import GeneralControls\nfrom src.gui.configtool.generalSettingsWidget import GeneralSettingsGroupBox\nfrom src.gui.configtool.graphicWidget import SimpleFOCGraphicWidget\nfrom src.gui.configtool.pidConfiguration import PidGroupBox\nfrom src.gui.configtool.torqueConfig import TorqueGroupBox\nfrom src.gui.sharedcomnponets.commandLineInterface import CommandLineWidget\nfrom src.gui.sharedcomnponets.sharedcomponets import (WorkAreaTabWidget,\n                                                      GUIToolKit)\nfrom src.simpleFOCConnector import SimpleFOCDevice\n\n\nclass DeviceConfigurationTool(WorkAreaTabWidget):\n\n    def __init__(self, parent=None):\n        super().__init__(parent)\n\n        self.device = SimpleFOCDevice.getInstance()\n\n        self.setObjectName('DeviceConfigurationTool')\n\n        self.verticalLayout = QtWidgets.QVBoxLayout(self)\n        self.verticalLayout.setObjectName('verticalLayout')\n\n        self.counterWidget = QtWidgets.QWidget(self)\n        self.counterWidget.setObjectName('counterWidget')\n        self.horizontalLayout = QtWidgets.QHBoxLayout(self.counterWidget)\n        self.horizontalLayout.setObjectName('horizontalLayout')\n        self.digitalReadOut = DROGroupBox(self.counterWidget)\n        self.horizontalLayout.addWidget(self.digitalReadOut)\n        \n        self.controlLoop = ControlLoopGroupBox(self.counterWidget)\n        self.horizontalLayout.addWidget(self.controlLoop)\n\n        self.torqueConfig = TorqueGroupBox(self.counterWidget)\n        self.horizontalLayout.addWidget(self.torqueConfig)\n\n        self.connectionControl = ConnectionControlGroupBox(self.counterWidget)\n        self.horizontalLayout.addWidget(self.connectionControl)\n        self.verticalLayout.addWidget(self.counterWidget)\n\n        self.graphicWidget = SimpleFOCGraphicWidget()\n        self.verticalLayout.addWidget(self.graphicWidget)\n\n        self.bottomWidget = QtWidgets.QWidget(self)\n        self.bottomWidget.setObjectName('bottomWidget')\n\n        self.bottomHorizontalLayout = QtWidgets.QHBoxLayout(self.bottomWidget)\n        self.bottomHorizontalLayout.setObjectName('configureHorizontalLayout')\n\n        self.pidConfigurator = PidGroupBox(self.bottomWidget)\n        self.bottomHorizontalLayout.addWidget(self.pidConfigurator)\n\n        self.generalLayout = QtWidgets.QVBoxLayout()\n        self.generalDeviceSettings = GeneralSettingsGroupBox(self.bottomWidget)\n\n        self.generalControls = GeneralControls(self.bottomWidget)\n        self.generalLayout.addWidget(self.generalControls)\n        self.generalLayout.addWidget(self.generalDeviceSettings)\n        self.bottomHorizontalLayout.addLayout(self.generalLayout)\n\n        self.lasWidget = QtWidgets.QWidget(self)\n        self.lastVerticalLayout = QtWidgets.QVBoxLayout(self.lasWidget)\n\n        self.commandLine = CommandLineWidget(self)\n        self.lastVerticalLayout.addWidget(self.commandLine)\n\n        self.joggingControl = DeviceJoggingControl(self)\n        self.lastVerticalLayout.addWidget(self.joggingControl)\n\n        self.bottomHorizontalLayout.addWidget(self.lasWidget)\n        self.verticalLayout.addWidget(self.bottomWidget)\n\n        self.device.commProvider.commandDataReceived.connect(self.commandLine.publishCommandResponseData)\n\n    def getTabIcon(self):\n        return GUIToolKit.getIconByName('motor')\n\n    def getTabName(self):\n        return self.device.connectionID\n\n    def configureConnection(self, configvalues):\n        self.device.serialPortName = configvalues['serialPortName']\n        self.device.serialRate = configvalues['serialRate']\n        self.device.stopBits = configvalues['stopBits']\n        self.device.serialByteSize = configvalues['serialByteSize']\n        self.device.serialParity = configvalues['serialParity']\n"
  },
  {
    "path": "src/gui/configtool/deviceInteractionFrame.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom PyQt5.QtCore import Qt\nfrom PyQt5.QtWidgets import (QVBoxLayout, QFrame, QSplitter)\n\nfrom src.gui.configtool.graphicWidget import SimpleFOCGraphicWidget\nfrom src.gui.sharedcomnponets.commandLineInterface import CommandLineWidget\nfrom src.simpleFOCConnector import SimpleFOCDevice\n\n\nclass DeviceInteractionFrame(QFrame):\n    def __init__(self, parent=None):\n        super().__init__(parent)\n\n        self.layout = QVBoxLayout(self)\n        self.setLayout(self.layout)\n        self.device = SimpleFOCDevice.getInstance()\n\n        self.graphicWidget = SimpleFOCGraphicWidget(self)\n        self.cmdLineTollWidget = CommandLineWidget(self)\n\n        self.cmdLineTollWidget.setMaximumHeight(150)\n\n        self.verticalSplitter = QSplitter(Qt.Vertical)\n        self.verticalSplitter.addWidget(self.graphicWidget)\n        self.verticalSplitter.addWidget(self.cmdLineTollWidget)\n        self.device.commProvider.commandDataReceived.connect(\n            self.cmdLineTollWidget.publishCommandResponseData)\n        self.layout.addWidget(self.verticalSplitter)\n\n        self.setLayout(self.layout)\n"
  },
  {
    "path": "src/gui/configtool/deviceJoggingControl.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\nfrom PyQt5 import (QtGui, QtWidgets, QtCore)\n\nfrom src.gui.sharedcomnponets.sharedcomponets import GUIToolKit\nfrom src.simpleFOCConnector import SimpleFOCDevice\n\n\nclass DeviceJoggingControl(QtWidgets.QGroupBox):\n    def __init__(self, parent=None):\n        super().__init__(parent)\n        self.device = SimpleFOCDevice.getInstance()\n\n        self.setObjectName('joggingControl')\n        self.setTitle('Jogging control')\n\n        self.horizontalLayout = QtWidgets.QHBoxLayout(self)\n        self.horizontalLayout.setObjectName('generalControlHL')\n\n        self.fastFordwardButton = QtWidgets.QPushButton()\n        self.fastFordwardButton.setObjectName('fastbackward')\n        self.fastFordwardButton.setIcon(GUIToolKit.getIconByName('fastbackward'))\n        self.fastFordwardButton.clicked.connect(self.joggingFastBackward)\n        self.horizontalLayout.addWidget(self.fastFordwardButton)\n\n        self.backwardButton = QtWidgets.QPushButton()\n        self.backwardButton.setObjectName('backward')\n        self.backwardButton.setIcon(GUIToolKit.getIconByName('backward'))\n        self.backwardButton.clicked.connect(self.joggingBackward)\n        self.horizontalLayout.addWidget(self.backwardButton)\n\n        self.stopButton = QtWidgets.QPushButton()\n        self.stopButton.setObjectName('stopbutton')\n        self.stopButton.setIcon(GUIToolKit.getIconByName('stopjogging'))\n        self.stopButton.clicked.connect(self.joggingStop)\n        self.horizontalLayout.addWidget(self.stopButton)\n\n        self.fordwardButton = QtWidgets.QPushButton()\n        self.fordwardButton.setObjectName('fordward')\n        self.fordwardButton.setIcon(GUIToolKit.getIconByName('fordward'))\n        self.fordwardButton.clicked.connect(self.joggingFordward)\n        self.horizontalLayout.addWidget(self.fordwardButton)\n\n        self.fastBackwardButton = QtWidgets.QPushButton()\n        self.fastBackwardButton.setObjectName('fastfordward')\n        self.fastBackwardButton.setIcon(GUIToolKit.getIconByName('fastfordward'))\n        self.fastBackwardButton.clicked.connect(self.joggingfastFordward)\n        self.horizontalLayout.addWidget(self.fastBackwardButton)\n\n        self.incrementLabel = QtWidgets.QLabel(\"Increment:\")\n        self.horizontalLayout.addWidget(self.incrementLabel)\n\n        onlyFloat = QtGui.QRegExpValidator(\n            QtCore.QRegExp(\"[+-]?([0-9]*[.])?[0-9]+\"))\n        self.incrementEdit = QtWidgets.QLineEdit()\n        self.incrementEdit.setValidator(onlyFloat)\n        self.incrementEdit.setAlignment(QtCore.Qt.AlignCenter)\n        self.incrementEdit.setText('1.0')\n        self.incrementEdit.setObjectName('incrementEdit')\n        self.horizontalLayout.addWidget(self.incrementEdit)\n\n        self.disableUI()\n        self.device.addConnectionStateListener(self)\n\n    def connectionStateChanged(self, isConnectedFlag):\n        if isConnectedFlag is True:\n            self.enabeUI()\n        else:\n            self.disableUI()\n    def enabeUI(self):\n        self.setEnabled(True)\n\n    def disableUI(self):\n        self.setEnabled(False)\n\n    def joggingFastBackward(self):\n        currenttarget = self.device.targetNow\n        increment = self.incrementEdit.text()\n        newTarget = float(currenttarget) - 2 * float(increment)\n        self.device.sendTargetValue(str(newTarget))\n    def joggingBackward(self):\n        increment = self.incrementEdit.text()\n        currenttarget = self.device.targetNow\n        newTarget = float(currenttarget) - float(increment)\n        self.device.sendTargetValue(str(newTarget))\n    def joggingStop(self):\n        controltType = self.device.controlType\n        if (controltType == SimpleFOCDevice.ANGLE_CONTROL or\n                controltType == SimpleFOCDevice.ANGLE_OPENLOOP_CONTROL):\n            self.device.sendTargetValue(self.device.angleNow)\n        if (controltType == SimpleFOCDevice.VELOCITY_CONTROL or\n                controltType == SimpleFOCDevice.VELOCITY_OPENLOOP_CONTROL):\n            self.device.sendTargetValue('0')\n    def joggingFordward(self):\n        increment = self.incrementEdit.text()\n        currenttarget = self.device.targetNow\n        newTarget = float(currenttarget) + float(increment)\n        self.device.sendTargetValue(str(newTarget))\n    def joggingfastFordward(self):\n        increment = self.incrementEdit.text()\n        currenttarget = self.device.targetNow\n        newTarget = float(currenttarget) + 2 * float(increment)\n        self.device.sendTargetValue(str(newTarget))"
  },
  {
    "path": "src/gui/configtool/deviceTreeview.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom PyQt5 import (QtWidgets,QtCore)\nfrom PyQt5.Qt import QTreeWidget\nfrom src.gui.sharedcomnponets.sharedcomponets import GUIToolKit\nfrom src.simpleFOCConnector import SimpleFOCDevice\nfrom src.simpleFOCConnector import Command\n\nclass DeviceTreeView(QTreeWidget):\n    def __init__(self, parent=None):\n        super().__init__(parent)\n\n        self.device = SimpleFOCDevice.getInstance()\n\n        self.sFOCDevice = QtWidgets.QTreeWidgetItem(self)\n        self.sFOCDevice.setText(0, 'sFOC Device')\n        self.sFOCDevice.setIcon(0, GUIToolKit.getIconByName('motor'))\n\n        self.setColumnCount(2)\n\n        self.motionControl = QtWidgets.QTreeWidgetItem(self.sFOCDevice)\n        self.motionControl.setText(0, 'Motion config')\n        self.motionControl.setIcon(0, GUIToolKit.getIconByName('pidconfig'))\n        self.sFOCDevice.addChild(self.motionControl)\n        \n        self.controller = QtWidgets.QTreeWidgetItem(self.motionControl)\n        self.controller.setText(0, 'Motion Control Type')\n        self.controller.setIcon(0, GUIToolKit.getIconByName('gear'))\n        self.selectorControlLoop = QtWidgets.QComboBox(self)\n        self.selectorControlLoop.addItems(['Torque', 'Velocity', 'Angle', 'Velocity openloop', 'Angle openloop'])\n        self.selectorControlLoop.currentIndexChanged.connect(self.changeControlLoop)\n        self.setItemWidget(self.controller,1,self.selectorControlLoop)\n\n        self.torque = QtWidgets.QTreeWidgetItem(self.motionControl)\n        self.torque.setText(0, 'Torque Control Type')\n        self.torque.setIcon(0, GUIToolKit.getIconByName('gear'))\n        self.selectorTorque = QtWidgets.QComboBox(self)\n        self.selectorTorque.addItems(['Voltage', 'DC Curret', 'FOC Current'])\n        self.selectorTorque.currentIndexChanged.connect(self.changeTorque)\n        self.setItemWidget(self.torque,1,self.selectorTorque)\n        \n        self.motionDownsample = QtWidgets.QTreeWidgetItem(self.motionControl)\n        self.motionDownsample.setText(0, 'Motion Downsample')\n        self.motionDownsample.setIcon(0, GUIToolKit.getIconByName('gear'))\n        self.motionDownsample.setText(1, '')\n        self.motionDownsample.setFlags(\n            self.motionDownsample.flags() | QtCore.Qt.ItemIsEditable)\n        \n        self.PIDVelocityConfig = self.addPIDSubtree(self.motionControl,'Velocity PID')\n        self.PIDAngleConfig = self.addPIDSubtree(self.motionControl,'Angle PID')\n        self.PIDCurrentQConfig = self.addPIDSubtree(self.motionControl,'Current q PID')\n        self.PIDCurrentDConfig = self.addPIDSubtree(self.motionControl,'Current d PID')\n\n        self.limitsConfig = QtWidgets.QTreeWidgetItem(self.sFOCDevice)\n        self.limitsConfig.setText(0, 'Limits')\n        self.limitsConfig.setIcon(0, GUIToolKit.getIconByName('statistics'))\n        self.sFOCDevice.addChild(self.limitsConfig)\n\n        self.velocityLimit = QtWidgets.QTreeWidgetItem(self.limitsConfig)\n        self.velocityLimit.setText(0, 'Velocity limit')\n        self.velocityLimit.setIcon(0, GUIToolKit.getIconByName('gear'))\n        self.velocityLimit.setText(1, '')\n        self.velocityLimit.setFlags(\n            self.velocityLimit.flags() | QtCore.Qt.ItemIsEditable)\n\n        self.voltageLimit = QtWidgets.QTreeWidgetItem(self.limitsConfig)\n        self.voltageLimit.setText(0, 'Voltage limit')\n        self.voltageLimit.setIcon(0, GUIToolKit.getIconByName('gear'))\n        self.voltageLimit.setText(1, '')\n        self.voltageLimit.setFlags(\n            self.voltageLimit.flags() | QtCore.Qt.ItemIsEditable)\n\n        self.currentLimit = QtWidgets.QTreeWidgetItem(self.limitsConfig)\n        self.currentLimit.setText(0, 'Current limit')\n        self.currentLimit.setIcon(0, GUIToolKit.getIconByName('gear'))\n        self.currentLimit.setText(1, '')\n        self.currentLimit.setFlags(\n            self.currentLimit.flags() | QtCore.Qt.ItemIsEditable)\n\n        self.statesConfig = QtWidgets.QTreeWidgetItem(self.sFOCDevice)\n        self.statesConfig.setText(0, 'States')\n        self.statesConfig.setIcon(0, GUIToolKit.getIconByName('statistics'))\n        self.sFOCDevice.addChild(self.statesConfig)\n\n        self.satateTarget = QtWidgets.QTreeWidgetItem(self.statesConfig)\n        self.satateTarget.setText(0, 'Target')\n        self.satateTarget.setIcon(0, GUIToolKit.getIconByName('gear'))\n        self.satateTarget.setText(1, '')\n\n        self.stateVq = QtWidgets.QTreeWidgetItem(self.statesConfig)\n        self.stateVq.setText(0, 'Voltage q')\n        self.stateVq.setIcon(0, GUIToolKit.getIconByName('gear'))\n        self.stateVd = QtWidgets.QTreeWidgetItem(self.statesConfig)\n        self.stateVd.setText(0, 'Voltage d')\n        self.stateVd.setIcon(0, GUIToolKit.getIconByName('gear'))\n\n        self.stateCq = QtWidgets.QTreeWidgetItem(self.statesConfig)\n        self.stateCq.setText(0, 'Current q')\n        self.stateCq.setIcon(0, GUIToolKit.getIconByName('gear'))\n        self.stateCd = QtWidgets.QTreeWidgetItem(self.statesConfig)\n        self.stateCd.setText(0, 'Current d')\n        self.stateCd.setIcon(0, GUIToolKit.getIconByName('gear'))\n\n        self.stateVel = QtWidgets.QTreeWidgetItem(self.statesConfig)\n        self.stateVel.setText(0, 'Velocity')\n        self.stateVel.setIcon(0, GUIToolKit.getIconByName('gear'))\n        self.stateVel.setText(1, '')\n\n        self.stateAngle = QtWidgets.QTreeWidgetItem(self.statesConfig)\n        self.stateAngle.setText(0, 'Angle')\n        self.stateAngle.setIcon(0, GUIToolKit.getIconByName('gear'))\n        self.stateAngle.setText(1, '')\n\n        self.sensorConfig = QtWidgets.QTreeWidgetItem(self.sFOCDevice)\n        self.sensorConfig.setText(0, 'Sensor config')\n        self.sensorConfig.setIcon(0, GUIToolKit.getIconByName('sensor'))\n        self.sFOCDevice.addChild(self.sensorConfig)\n\n        self.sensorZeroOffset = QtWidgets.QTreeWidgetItem(self.sensorConfig)\n        self.sensorZeroOffset.setText(0, 'Zero Angle Offset')\n        self.sensorZeroOffset.setIcon(0, GUIToolKit.getIconByName('gear'))\n        self.sensorZeroOffset.setText(1, '')\n        self.sensorZeroOffset.setFlags(\n            self.sensorZeroOffset.flags() | QtCore.Qt.ItemIsEditable)\n\n        self.sensorZeroElecOffset = QtWidgets.QTreeWidgetItem(self.sensorConfig)\n        self.sensorZeroElecOffset.setText(0, 'Electrical Zero Offset')\n        self.sensorZeroElecOffset.setIcon(0, GUIToolKit.getIconByName('gear'))\n        self.sensorZeroElecOffset.setText(1, '')\n        self.sensorZeroElecOffset.setFlags(\n            self.sensorZeroElecOffset.flags() | QtCore.Qt.ItemIsEditable)\n\n        self.generalSettings = QtWidgets.QTreeWidgetItem(self.sFOCDevice)\n        self.generalSettings.setText(0, 'General settings')\n        self.generalSettings.setIcon(0, GUIToolKit.getIconByName('generalsettings'))\n        self.sFOCDevice.addChild(self.generalSettings)\n\n        self.phaseRes = QtWidgets.QTreeWidgetItem(self.generalSettings)\n        self.phaseRes.setText(0, 'Phase Resistance')\n        self.phaseRes.setIcon(0, GUIToolKit.getIconByName('res'))\n        self.phaseRes.setText(1, '')\n        self.phaseRes.setFlags(\n            self.phaseRes.flags() | QtCore.Qt.ItemIsEditable)\n\n        self.deviceStatus = QtWidgets.QTreeWidgetItem(self.generalSettings)\n        self.deviceStatus.setText(0, 'Motor Status')\n        self.deviceStatus.setIcon(0, GUIToolKit.getIconByName('gear'))\n        self.selectStatus = QtWidgets.QComboBox(self)\n        self.selectStatus.addItems(['Disabled', 'Enabled'])\n        self.selectStatus.currentIndexChanged.connect(self.changeStatus)\n        self.setItemWidget(self.deviceStatus,1,self.selectStatus)\n\n        self.modulationType = QtWidgets.QTreeWidgetItem(self.generalSettings)\n        self.modulationType.setText(0, 'PWM modulation')\n        self.modulationType.setIcon(0, GUIToolKit.getIconByName('gear'))\n        self.selectModulation = QtWidgets.QComboBox(self)\n        self.selectModulation.addItems(['Sine PWM', 'Space Vector PWM', 'Trapezoidal 120', 'Trapezoidal 150'])\n        self.selectModulation.currentIndexChanged.connect(self.changeModType)\n        self.setItemWidget(self.modulationType,1,self.selectModulation)\n\n        self.modulationCenter = QtWidgets.QTreeWidgetItem(self.generalSettings)\n        self.modulationCenter.setText(0, 'Modulation center')\n        self.modulationCenter.setIcon(0, GUIToolKit.getIconByName('gear'))\n        self.selectModCenter = QtWidgets.QComboBox(self)\n        self.selectModCenter.addItems(['Disabled', 'Enabled'])\n        self.selectModCenter.currentIndexChanged.connect(self.changeModCenter)\n        self.setItemWidget(self.modulationCenter,1,self.selectModCenter)\n\n        self.customComands = QtWidgets.QTreeWidgetItem(self.sFOCDevice)\n        self.customComands.setText(0, 'Custom commands')\n        self.customComands.setIcon(0, GUIToolKit.getIconByName('customcommands'))\n        self.sFOCDevice.addChild(self.customComands)\n\n        for customCommand in self.device.customCommands.customCommandsList:\n            self.initCustomCommand(customCommand)\n\n        self.installEventFilter(self)\n        self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)\n        self.customContextMenuRequested.connect(self.customCommandsMenu)\n\n        self.header().resizeSection(0,230)\n\n        self.setAlternatingRowColors(True)\n        self.header().hide()\n        self.expandItem(self.sFOCDevice)\n        self.expandItem(self.motionControl)\n\n        self.device.addConnectionStateListener(self)\n        self.device.commProvider.commandDataReceived.connect(self.commandResponseReceived)\n        self.device.commProvider.stateMonitorReceived.connect(self.stateResponseReceived)\n\n        self.itemChanged.connect(self.treeItemEdited)\n\n        self.setEnabled(self.device.isConnected)\n\n    def customCommandsMenu(self, position):\n        indexes = self.selectedIndexes()\n        if len(indexes) > 0:\n            level = 0\n            index = indexes[0]\n            while index.parent().isValid():\n                index = index.parent()\n                level += 1\n        selectedItem = self.selectedItems()[0]\n        menu = QtWidgets.QMenu()\n        if selectedItem.text(0) == 'Custom commands':\n            addComand = QtWidgets.QAction(\"Add command\", self)\n            addComand.triggered.connect(self.addCommandAction)\n            menu.addAction(addComand)\n        elif hasattr(selectedItem, 'isCustomCommand'):\n            executeCommand = QtWidgets.QAction(\"Execute\", self)\n            executeCommand.triggered.connect(self.executeCustomCommandAction)\n            menu.addAction(executeCommand)\n            deleteCommand = QtWidgets.QAction(\"Remove\", self)\n            deleteCommand.triggered.connect(self.deleteCustomCommand)\n            menu.addAction(deleteCommand)\n\n        menu.exec_(self.viewport().mapToGlobal(position))\n\n    def addCommandAction(self):\n        selectedItem = self.selectedItems()[0]\n        self.addCustomCommand(selectedItem)\n\n    def executeCustomCommandAction(self):\n        selectedItem = self.selectedItems()[0]\n        selectedCustomCommand = selectedItem.text(1)\n        self.device.sendCommand(selectedCustomCommand)\n\n    def deleteCustomCommand(self):\n        root = self.invisibleRootItem()\n        deletedIndex = self.customComands.indexOfChild(self.selectedItems()[0])\n        self.device.customCommands.customCommandsList.pop(deletedIndex)\n        for item in self.selectedItems():\n            (item.parent() or root).removeChild(item)\n\n    def eventFilter(self, obj, event):\n        if event.type() == QtCore.QEvent.KeyPress:\n            if event.key() == QtCore.Qt.Key_Return:\n                selectedItem = self.selectedItems()[0]\n                if selectedItem.text(0) == 'Custom commands':\n                    self.addCustomCommand(selectedItem)\n            if event.key() == QtCore.Qt.Key_Space or event.key() == QtCore.Qt.Key_Right:\n                selectedItem = self.selectedItems()[0]\n                if selectedItem.parent().text(0) == 'Custom commands':\n                    self.executeCustomCommandAction()\n            if event.key() == QtCore.Qt.Key_Delete or event.key() == QtCore.Qt.Key_Backspace:\n                selectedItem = self.selectedItems()[0]\n                if selectedItem.parent().text(0) == 'Custom commands':\n                    self.deleteCustomCommand()\n        return super(DeviceTreeView, self).eventFilter(obj, event)\n\n    def addCustomCommand(sefl,selectedItem):\n        customCommand = QtWidgets.QTreeWidgetItem()\n        customCommand.isCustomCommand = True\n        customCommand.setText(0, 'Command')\n        customCommand.setIcon(0, GUIToolKit.getIconByName('gear'))\n\n        customCommand.setFlags(\n            customCommand.flags() | QtCore.Qt.ItemIsEditable)\n        selectedItem.addChild(customCommand)\n        sefl.device.customCommands.customCommandsList.append(Command('Command',''))\n\n    def initCustomCommand(sefl, command):\n        customCommand = QtWidgets.QTreeWidgetItem()\n        customCommand.isCustomCommand = True\n        customCommand.setText(0, command.cmdName)\n        customCommand.setText(1, command.cmd)\n        customCommand.setIcon(0, GUIToolKit.getIconByName('gear'))\n        customCommand.setFlags(\n            customCommand.flags() | QtCore.Qt.ItemIsEditable)\n        sefl.customComands.addChild(customCommand)\n\n    def addPIDSubtree(self, parent,  label):\n        pidConfiguration = QtWidgets.QTreeWidgetItem()\n        pidConfiguration.setText(0, label)\n        pidConfiguration.setIcon(0, GUIToolKit.getIconByName('pidconfig'))\n        parent.addChild(pidConfiguration)\n\n        proportionalGain = QtWidgets.QTreeWidgetItem(pidConfiguration)\n        proportionalGain.setText(0, 'Proportional gain')\n        proportionalGain.setIcon(0, GUIToolKit.getIconByName('gear'))\n        proportionalGain.setText(1, '')\n        proportionalGain.setFlags(\n            proportionalGain.flags() | QtCore.Qt.ItemIsEditable)\n\n        integralGain = QtWidgets.QTreeWidgetItem(pidConfiguration)\n        integralGain.setText(0, 'Integral gain')\n        integralGain.setIcon(0, GUIToolKit.getIconByName('gear'))\n        integralGain.setText(1, '')\n        integralGain.setFlags(\n            integralGain.flags() | QtCore.Qt.ItemIsEditable)\n\n        derivativeGain = QtWidgets.QTreeWidgetItem(pidConfiguration)\n        derivativeGain.setText(0, 'Derivative gain')\n        derivativeGain.setIcon(0, GUIToolKit.getIconByName('gear'))\n        derivativeGain.setText(1, '')\n        derivativeGain.setFlags(\n            derivativeGain.flags() | QtCore.Qt.ItemIsEditable)\n\n        voltageRamp = QtWidgets.QTreeWidgetItem(pidConfiguration)\n        voltageRamp.setText(0, 'Output Ramp')\n        voltageRamp.setIcon(0, GUIToolKit.getIconByName('gear'))\n        voltageRamp.setText(1, '')\n        voltageRamp.setFlags(\n            voltageRamp.flags() | QtCore.Qt.ItemIsEditable)\n        \n        limit = QtWidgets.QTreeWidgetItem(pidConfiguration)\n        limit.setText(0, 'Output Limit')\n        limit.setIcon(0, GUIToolKit.getIconByName('gear'))\n        limit.setText(1, '')\n        limit.setFlags(\n            limit.flags() | QtCore.Qt.ItemIsEditable)\n\n        lpfTf = QtWidgets.QTreeWidgetItem(pidConfiguration)\n        lpfTf.setText(0, 'Low pass filter')\n        lpfTf.setIcon(0, GUIToolKit.getIconByName('gear'))\n        lpfTf.setText(1, '')\n        lpfTf.setFlags(\n            lpfTf.flags() | QtCore.Qt.ItemIsEditable)\n\n        return pidConfiguration\n\n    def treeItemEdited(self, item, column):\n        if item.parent().text(0) == 'Custom commands':\n            updatedIndex = self.customComands.indexOfChild(item)\n            updatedValue = item.text(column)\n            if column == 0:\n                self.device.customCommands.customCommandsList[\n                    updatedIndex].cmdName = updatedValue\n            else:\n                self.device.customCommands.customCommandsList[\n                    updatedIndex].cmd = updatedValue\n        else:\n            self.sendCommand(item, column)\n\n    def sendCommand(self, item, column):\n        value = item.text(1)\n        fieldName = item.text(0)\n        pidLabel = item.parent().text(0)\n        pid = {}\n        lpf = {}\n        if 'Velocity PID' in pidLabel:\n            pid = self.device.PIDVelocity\n            lpf = self.device.LPFVelocity\n        elif 'Angle PID' in pidLabel:\n            pid = self.device.PIDAngle\n            lpf = self.device.LPFAngle\n        elif 'Current q PID' in pidLabel:\n            pid = self.device.PIDCurrentQ\n            lpf = self.device.LPFCurrentQ\n        elif 'Current d PID' in pidLabel:\n            pid = self.device.PIDCurrentD\n            lpf = self.device.LPFCurrentD\n\n        if 'Proportional gain' in fieldName:\n            self.device.sendProportionalGain(pid, value)\n        elif 'Integral gain' in fieldName:\n            self.device.sendIntegralGain(pid, value)\n        elif 'Derivative gain' in fieldName:\n            self.device.sendDerivativeGain(pid, value)\n        elif 'Output Ramp' in fieldName:\n            self.device.sendOutputRamp(pid, value)\n        elif 'Low pass filter' in fieldName:\n            self.device.sendLowPassFilter(lpf, value)\n        elif 'Output Limit' in fieldName:\n            self.device.sendOutputLimit(pid,value)\n        elif 'Voltage limit' in fieldName:\n            self.device.sendVoltageLimit(value)\n        elif 'Velocity limit' in fieldName:\n            self.device.sendVelocityLimit(value)\n        elif 'Current limit' in fieldName:\n            self.device.sendCurrentLimit(value)\n        elif 'Phase Resistance' in fieldName:\n            self.device.sendPhaseResistance(value)\n        elif 'Zero Angle Offset' in fieldName:\n            self.device.sendSensorZeroOffset(value)\n        elif 'Electrical Zero Offset' in fieldName:\n            self.device.sendSensorZeroElectrical(value)\n        elif 'Motion Downsample' in fieldName:\n            self.device.sendMotionDownsample(value)\n\n    def refreshPIDSubtree(self, pidDisp, pidVal, lpfVal):\n        pidDisp.child(0).setText(1,str(pidVal.P))\n        pidDisp.child(1).setText(1,str(pidVal.I))\n        pidDisp.child(2).setText(1,str(pidVal.D))\n        pidDisp.child(3).setText(1,str(pidVal.outputRamp))\n        pidDisp.child(4).setText(1,str(pidVal.outputLimit))\n        pidDisp.child(5).setText(1,str(lpfVal.Tf))\n\n    def commandResponseReceived(self, comandResponse):\n        self.refreshDeviceTree()\n        self.setTorqueMode(self.device.torqueType)\n        self.setControlLopMode(self.device.controlType)\n        self.setEnabledDisabled(self.device.deviceStatus)\n        self.setModCenter(self.device.modulationCentered)\n        self.setModType(self.device.modulationType)\n\n    def stateResponseReceived(self, comandResponse):\n        self.blockSignals(True)\n        self.stateVel.setText(1,str(self.device.velocityNow))\n        self.stateAngle.setText(1,str(self.device.angleNow))\n        self.stateVd.setText(1,str(self.device.voltageDNow))\n        self.stateVq.setText(1,str(self.device.voltageQNow))\n        self.stateCq.setText(1,str(self.device.currentQNow))\n        self.stateCd.setText(1,str(self.device.currentDNow))\n        self.satateTarget.setText(1,str(self.device.targetNow))\n        self.update()\n        self.blockSignals(False)\n\n    def refreshDeviceTree(self):\n        self.blockSignals(True)\n\n        self.refreshPIDSubtree( self.PIDVelocityConfig, self.device.PIDVelocity, self.device.LPFVelocity)\n        self.refreshPIDSubtree( self.PIDAngleConfig, self.device.PIDAngle, self.device.LPFAngle)\n        self.refreshPIDSubtree( self.PIDCurrentQConfig, self.device.PIDCurrentQ, self.device.LPFCurrentQ)\n        self.refreshPIDSubtree( self.PIDCurrentDConfig, self.device.PIDCurrentD, self.device.LPFCurrentD)\n\n        self.voltageLimit.setText(1,str(self.device.voltageLimit))\n        self.velocityLimit.setText(1,str(self.device.velocityLimit))\n        self.currentLimit.setText(1,str(self.device.currentLimit))\n\n        self.sensorZeroOffset.setText(1,str(self.device.sensorZeroOffset))\n        self.sensorZeroElecOffset.setText(1,str(self.device.sensorElectricalZero))\n        \n        self.phaseRes.setText(1,str(self.device.phaseResistance))\n        # self.deviceStatus.setText(1,str(self.device.deviceStatus))\n\n        self.motionDownsample.setText(1,str(self.device.motionDownsample))\n        # self.torque.setText(1,str(self.device.torqueType))\n        # self.controller.setText(1,str(self.device.controlType))\n        self.update()\n        self.blockSignals(False)\n\n    def setTorqueMode(self, value):\n        self.blockSignals(True)\n        if value == SimpleFOCDevice.VOLTAGE_TORQUE:\n            self.selectorTorque.setCurrentIndex(0)\n        elif value == SimpleFOCDevice.DC_CURRENT_TORQUE:\n            self.selectorTorque.setCurrentIndex(1)\n        elif value == SimpleFOCDevice.FOC_CURRENT_TORQUE:\n            self.selectorTorque.setCurrentIndex(2)\n        self.blockSignals(False)\n\n    def changeTorque(self):\n        index = self.selectorTorque.currentIndex()\n        if index == 0:\n            self.device.sendTorqueType(SimpleFOCDevice.VOLTAGE_TORQUE)\n        elif index == 1:\n            self.device.sendTorqueType(SimpleFOCDevice.DC_CURRENT_TORQUE)\n        elif index == 2:\n            self.device.sendTorqueType(SimpleFOCDevice.FOC_CURRENT_TORQUE)\n\n    def setEnabledDisabled(self, value):\n        self.blockSignals(True)\n        if value == 0:\n            self.selectStatus.setCurrentIndex(0)\n        elif value == 1:\n            self.selectStatus.setCurrentIndex(1)\n        self.blockSignals(False)\n\n    def changeStatus(self):\n        index = self.selectStatus.currentIndex()\n        if index == 0:\n            self.device.sendDeviceStatus(0)\n        elif index == 1:\n            self.device.sendDeviceStatus(1)\n        \n    def setModCenter(self,value):\n        self.blockSignals(True)\n        self.selectModCenter.setCurrentIndex(int(value))\n        self.blockSignals(False)\n        \n    def changeModCenter(self):\n        index = self.selectModCenter.currentIndex()\n        if index == 0:\n            self.device.sendModulationCentered(0)\n        elif index == 1:\n            self.device.sendModulationCentered(1)\n\n    def setModType(self, value):\n        self.blockSignals(True)\n        if value == SimpleFOCDevice.SINE_PWM:\n            self.selectModulation.setCurrentIndex(0)\n        elif value == SimpleFOCDevice.SPACE_VECTOR_PWM:\n            self.selectModulation.setCurrentIndex(1)\n        elif value == SimpleFOCDevice.TRAPEZOIDAL_120:\n            self.selectModulation.setCurrentIndex(2)\n        elif value == SimpleFOCDevice.TRAPEZOIDAL_150:\n            self.selectModulation.setCurrentIndex(3)\n        self.blockSignals(False)\n\n    def changeModType(self):\n        index = self.selectModulation.currentIndex()\n        if index == 0:\n            self.device.sendModulationType(SimpleFOCDevice.SINE_PWM)\n        elif index == 1:\n            self.device.sendModulationType(SimpleFOCDevice.SPACE_VECTOR_PWM)\n        elif index == 2:\n            self.device.sendModulationType(SimpleFOCDevice.TRAPEZOIDAL_120)\n        elif index == 3:\n            self.device.sendModulationType(SimpleFOCDevice.TRAPEZOIDAL_150)\n\n    def setControlLopMode(self, value):\n        self.blockSignals(True)\n        if value == SimpleFOCDevice.TORQUE_CONTROL:\n            self.selectorControlLoop.setCurrentIndex(0)\n        elif value == SimpleFOCDevice.VELOCITY_CONTROL:\n            self.selectorControlLoop.setCurrentIndex(1)\n        elif value == SimpleFOCDevice.ANGLE_CONTROL:\n            self.selectorControlLoop.setCurrentIndex(2)\n        elif value == SimpleFOCDevice.VELOCITY_OPENLOOP_CONTROL:\n            self.selectorControlLoop.setCurrentIndex(3)\n        elif value == SimpleFOCDevice.ANGLE_OPENLOOP_CONTROL:\n            self.selectorControlLoop.setCurrentIndex(4)\n        self.blockSignals(False)\n\n    def changeControlLoop(self):\n        index = self.selectorControlLoop.currentIndex()\n        if index == 0:\n            self.device.sendControlType(SimpleFOCDevice.TORQUE_CONTROL)\n        elif index == 1:\n            self.device.sendControlType(SimpleFOCDevice.VELOCITY_CONTROL)\n        elif index == 2:\n            self.device.sendControlType(SimpleFOCDevice.ANGLE_CONTROL)\n        elif index == 3:\n            self.device.sendControlType(SimpleFOCDevice.VELOCITY_OPENLOOP_CONTROL)\n        elif index == 4:\n            self.device.sendControlType(SimpleFOCDevice.ANGLE_OPENLOOP_CONTROL)\n    \n    def connectionStateChanged(self, connectionFlag):\n        if connectionFlag is True:\n            self.setEnabled(True)\n        else:\n            self.setEnabled(False)\n"
  },
  {
    "path": "src/gui/configtool/devicesInspectorTree.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom PyQt5.QtWidgets import (QVBoxLayout, QFrame)\n\nfrom src.gui.configtool.connectionControl import ConnectionControlGroupBox\nfrom src.gui.configtool.deviceJoggingControl import DeviceJoggingControl\nfrom src.gui.configtool.deviceTreeview import DeviceTreeView\nfrom src.gui.configtool.droDisplayWidget import DROGroupBox\nfrom src.gui.configtool.generalControls import GeneralControls\nfrom src.simpleFOCConnector import SimpleFOCDevice\n\n\nclass DevicesInspectorTree(QFrame):\n    def __init__(self, parent=None):\n        super().__init__(parent)\n        self.device = SimpleFOCDevice.getInstance()\n\n        self.layout = QVBoxLayout(self)\n        self.setLayout(self.layout)\n\n        self.droWidget = DROGroupBox(self)\n        self.layout.addWidget(self.droWidget)\n\n        self.generalControls = GeneralControls(self)\n        self.layout.addWidget(self.generalControls)\n\n        self.treeView = DeviceTreeView(self)\n        self.layout.addWidget(self.treeView)\n\n        self.joggingControl = DeviceJoggingControl(self)\n        self.layout.addWidget(self.joggingControl)\n\n        self.connectionControl = ConnectionControlGroupBox(self)\n        self.layout.addWidget(self.connectionControl)\n\n        self.setMaximumWidth(500)\n"
  },
  {
    "path": "src/gui/configtool/droDisplayWidget.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\nfrom PyQt5 import (QtGui,QtWidgets)\n\nfrom src.gui.sharedcomnponets.sharedcomponets import GUIToolKit\nfrom src.simpleFOCConnector import SimpleFOCDevice\n\n\nclass DROGroupBox(QtWidgets.QGroupBox):\n\n    def __init__(self, parent=None):\n        super().__init__(parent)\n\n        self.device = SimpleFOCDevice.getInstance()\n\n        self.setTitle('Simple FOC Digital Read Out')\n        self.setObjectName('digitalReadOut')\n\n        self.droHorizontalLayout = QtWidgets.QHBoxLayout(self)\n        self.droHorizontalLayout.setObjectName('droHorizontalLayout')\n\n        self.signal0Label = QtWidgets.QLabel(self)\n        self.signal0Label.setObjectName('angleLabel')\n        self.signal0Label.setText('Angle')\n        self.droHorizontalLayout.addWidget(self.signal0Label)\n\n        self.signal0LCDNumber = QtWidgets.QLCDNumber(self)\n        self.putStyleToLCDNumber(self.signal0LCDNumber)\n        self.signal0LCDNumber.setObjectName('signal0LCDNumber')\n        self.droHorizontalLayout.addWidget(self.signal0LCDNumber)\n\n        self.signal1Label = QtWidgets.QLabel(self)\n        self.signal1Label.setObjectName('velLabel')\n        self.signal1Label.setText('Velocity')\n        self.droHorizontalLayout.addWidget(self.signal1Label)\n\n        self.signal1LCDNumber = QtWidgets.QLCDNumber(self)\n        self.putStyleToLCDNumber(self.signal1LCDNumber)\n        self.signal1LCDNumber.setObjectName('signal1LCDNumber')\n        self.droHorizontalLayout.addWidget(self.signal1LCDNumber)\n\n        self.signal2Label = QtWidgets.QLabel(self)\n        self.signal2Label.setObjectName('torqueLabel')\n        self.signal2Label.setText('Target')\n        self.droHorizontalLayout.addWidget(self.signal2Label)\n\n        self.signal2LCDNumber = QtWidgets.QLCDNumber(self)\n        self.putStyleToLCDNumber(self.signal2LCDNumber)\n        self.signal2LCDNumber.setObjectName('signal2LCDNumber')\n        self.droHorizontalLayout.addWidget(self.signal2LCDNumber)\n\n        self.signal3Label = QtWidgets.QLabel(self)\n        self.signal3Label.setObjectName('targetLabel')\n        self.signal3Label.setText('Target')\n        self.droHorizontalLayout.addWidget(self.signal3Label)\n\n        self.signal3LCDNumber = QtWidgets.QLCDNumber(self)\n        self.putStyleToLCDNumber(self.signal3LCDNumber)\n        self.signal3LCDNumber.setObjectName('signal3LCDNumber')\n        self.droHorizontalLayout.addWidget(self.signal3LCDNumber)\n\n        self.commandResponseReceived('init')\n\n        self.initDiplay()\n        self.disableUI()\n\n        self.device.addConnectionStateListener(self)\n        self.device.commProvider.stateMonitorReceived.connect(self.commandResponseReceived)\n\n        self.connectionStateChanged(self.device.isConnected)\n\n    def connectionStateChanged(self, isConnectedFlag):\n        if isConnectedFlag is True:\n            self.enabeUI()\n            self.initDiplay()\n        else:\n            self.initDiplay()\n            self.disableUI()\n\n    def enabeUI(self):\n        self.setEnabled(True)\n\n    def disableUI(self):\n        self.setEnabled(False)\n\n    def initDiplay(self):\n        self.signal0LCDNumber.display(0.0)\n        self.signal1LCDNumber.display(0.0)\n        self.signal2LCDNumber.display(0.0)\n        self.signal3LCDNumber.display(0.0)\n\n    def putStyleToLCDNumber(self, lcdNumber):\n        lcdNumber.setStyleSheet('''QLCDNumber {background-color: white;}''')\n        palette = self.setColor(lcdNumber.palette(), GUIToolKit.RED_COLOR)\n        lcdNumber.setPalette(palette)\n\n    def setColor(self, palette, colorTouple):\n        R = colorTouple[0]\n        G = colorTouple[1]\n        B = colorTouple[2]\n        # foreground color\n        palette.setColor(palette.WindowText, QtGui.QColor(R, G, B))\n        # background color\n        palette.setColor(palette.Background, QtGui.QColor(R, G, B))\n        # 'light' border\n        palette.setColor(palette.Light, QtGui.QColor(R, G, B))\n        # 'dark' border\n        palette.setColor(palette.Dark, QtGui.QColor(R, G, B))\n        return palette\n\n    def commandResponseReceived(self, cmdRespose):        \n        if self.device.torqueType ==  SimpleFOCDevice.VOLTAGE_TORQUE:\n            self.signal2Label.setText(\"Voltage\")\n            self.signal2LCDNumber.display(self.device.voltageQNow)\n        else: # dc current or FOC current\n            self.signal2Label.setText(\"Current\")\n            self.signal2LCDNumber.display(self.device.currentQNow)\n\n        self.signal3LCDNumber.display(self.device.targetNow)\n        self.signal1LCDNumber.display(self.device.velocityNow)\n        self.signal0LCDNumber.display(self.device.angleNow)\n"
  },
  {
    "path": "src/gui/configtool/generalControls.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom PyQt5 import (QtGui, QtWidgets, QtCore)\n\nfrom src.gui.sharedcomnponets.sharedcomponets import GUIToolKit\nfrom src.simpleFOCConnector import SimpleFOCDevice\n\n\nclass GeneralControls(QtWidgets.QGroupBox):\n\n    def __init__(self, parent=None):\n\n        super().__init__(parent)\n\n        # self.setMaximumWidth(300)\n\n        onlyFloat = QtGui.QRegExpValidator(\n            QtCore.QRegExp(\"[+-]?([0-9]*[.])?[0-9]+\"))\n\n        self.device = SimpleFOCDevice.getInstance()\n\n        self.setTitle('General Controls')\n\n        self.setObjectName('generalControls')\n\n        self.gcGridLayout = QtWidgets.QGridLayout(self)\n        self.gcGridLayout.setObjectName('gcGridLayout')\n\n\n        self.enableDeviceButton = QtWidgets.QPushButton(self)\n        self.enableDeviceButton.setObjectName('enButton')\n        self.enableDeviceButton.setText('Enable Device')\n        self.enableDeviceButton.setIcon(GUIToolKit.getIconByName('greendot'))\n        self.enableDeviceButton.clicked.connect(self.toggleEnable)\n        self.gcGridLayout.addWidget(self.enableDeviceButton, 1, 0, 1, 1)\n\n        self.sensorZeroButton = QtWidgets.QPushButton(self)\n        self.sensorZeroButton.setObjectName('homeButton')\n        self.sensorZeroButton.setText('Sensor Zero')\n        self.sensorZeroButton.setIcon(GUIToolKit.getIconByName('home'))\n        self.sensorZeroButton.clicked.connect(self.setSensorZero)\n        self.gcGridLayout.addWidget(self.sensorZeroButton, 1, 1, 1, 1)\n\n        self.setZeroTarget = QtWidgets.QPushButton(self)\n        self.setZeroTarget.setObjectName('zeroButton')\n        self.setZeroTarget.setText('Zero Target')\n        self.setZeroTarget.setIcon(GUIToolKit.getIconByName('stop'))\n        self.setZeroTarget.clicked.connect(self.setTargetZero)\n        self.gcGridLayout.addWidget(self.setZeroTarget, 1, 2, 1, 1)\n        self.reloadValues()\n\n        self.device.addConnectionStateListener(self)\n        self.device.commProvider.commandDataReceived.connect(self.commandResponseReceived)\n\n        self.connectionStateChanged(self.device.isConnected)\n\n    def connectionStateChanged(self, deviceConnected):\n        if deviceConnected is True:\n            self.enabeUI()\n        else:\n            self.disableUI()\n\n    def enabeUI(self):\n        self.setEnabled(True)\n\n    def disableUI(self):\n        self.setEnabled(False)\n\n    def setSensorZero(self):\n        val = self.device.angleNow + self.device.sensorZeroOffset\n        self.device.sendSensorZeroOffset(val)\n\n    def setTargetZero(self):\n        self.device.sendTargetValue(0)\n    \n    def toggleEnable(self):\n        val = int( not self.device.deviceStatus)\n        self.device.sendDeviceStatus(val)\n\n    def commandResponseReceived(self, comandResponse):\n        self.reloadValues()\n        \n    def reloadValues(self):\n        if self.device.deviceStatus:\n            self.enableDeviceButton.setText('Disable Device')\n            self.enableDeviceButton.setIcon(GUIToolKit.getIconByName('reddot'))\n        else:\n            self.enableDeviceButton.setText('Enable Device')\n            self.enableDeviceButton.setIcon(GUIToolKit.getIconByName('greendot'))"
  },
  {
    "path": "src/gui/configtool/generalSettingsWidget.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom PyQt5 import (QtGui, QtWidgets, QtCore)\n\nfrom src.gui.sharedcomnponets.sharedcomponets import ConfigQLineEdit\nfrom src.simpleFOCConnector import SimpleFOCDevice\n\n\nclass GeneralSettingsGroupBox(QtWidgets.QGroupBox):\n\n    def __init__(self, parent=None):\n\n        super().__init__(parent)\n\n        self.setMaximumWidth(300)\n\n        onlyFloat = QtGui.QRegExpValidator(\n            QtCore.QRegExp(\"[+-]?([0-9]*[.])?[0-9]+\"))\n\n        self.device = SimpleFOCDevice.getInstance()\n\n        self.setTitle('General device settings')\n\n        self.setObjectName('generalDeviceSettings')\n\n        self.gcGridLayout = QtWidgets.QGridLayout(self)\n        self.gcGridLayout.setObjectName('gcGridLayout')\n\n        self.motionDownsample = QtWidgets.QLabel(self)\n        self.motionDownsample.setObjectName('motionDownsample')\n        self.motionDownsample.setText('Motion Downsample')\n        self.gcGridLayout.addWidget(self.motionDownsample, 2, 0, 1, 1)\n\n        self.motionDownsampleEdit = ConfigQLineEdit(self)\n        self.motionDownsampleEdit.setObjectName('motionDownsampleEdit')\n        self.motionDownsampleEdit.setValidator(onlyFloat)\n        self.motionDownsampleEdit.setAlignment(QtCore.Qt.AlignCenter)\n        self.motionDownsampleEdit.updateValue.connect(self.sendMotionDownsampleAction)\n        self.gcGridLayout.addWidget(self.motionDownsampleEdit, 2, 1, 1, 1)\n\n        self.curLimitLabel = QtWidgets.QLabel(self)\n        self.curLimitLabel.setObjectName('curLimitLabel')\n        self.curLimitLabel.setText('Current Limit')\n        self.gcGridLayout.addWidget(self.curLimitLabel, 3, 0, 1, 1)\n\n        self.velLimitlabel = QtWidgets.QLabel(self)\n        self.velLimitlabel.setObjectName('velLimitlabel')\n        self.velLimitlabel.setText('Velocity limit')\n        self.gcGridLayout.addWidget(self.velLimitlabel, 4, 0, 1, 1)\n\n        self.volLimitLabel = QtWidgets.QLabel(self)\n        self.volLimitLabel.setObjectName('volLimitLabel')\n        self.volLimitLabel.setText('Voltage limit')\n        self.gcGridLayout.addWidget(self.volLimitLabel, 6, 0, 1, 1)\n\n        self.clLineEdit = ConfigQLineEdit(self)\n        self.clLineEdit.setObjectName('clLineEdit')\n        self.clLineEdit.setValidator(onlyFloat)\n        self.clLineEdit.setAlignment(QtCore.Qt.AlignCenter)\n        self.clLineEdit.updateValue.connect(self.sendCurrentLimitAction)\n        self.gcGridLayout.addWidget(self.clLineEdit, 3, 1, 1, 1)\n\n        self.vlLineEdit = ConfigQLineEdit(self)\n        self.vlLineEdit.setObjectName('vlLineEdit')\n        self.vlLineEdit.setValidator(onlyFloat)\n        self.vlLineEdit.setAlignment(QtCore.Qt.AlignCenter)\n        self.vlLineEdit.updateValue.connect(self.sendVelLimitAction)\n        self.gcGridLayout.addWidget(self.vlLineEdit, 4, 1, 1, 1)\n\n        self.volLLineEdit = ConfigQLineEdit(self)\n        self.volLLineEdit.setObjectName('volLLineEdit')\n        self.volLLineEdit.setValidator(onlyFloat)\n        self.volLLineEdit.setAlignment(QtCore.Qt.AlignCenter)\n        self.volLLineEdit.updateValue.connect(self.sendVoltageLimitAction)\n        self.gcGridLayout.addWidget(self.volLLineEdit, 6, 1, 1, 1)\n\n        self.reloadValues()\n\n        self.device.addConnectionStateListener(self)\n        self.device.commProvider.commandDataReceived.connect(self.commandResponseReceived)\n\n        self.connectionStateChanged(self.device.isConnected)\n\n    def connectionStateChanged(self, deviceConnected):\n        if deviceConnected is True:\n            self.enabeUI()\n        else:\n            self.disableUI()\n\n    def enabeUI(self):\n        self.setEnabled(True)\n\n    def disableUI(self):\n        self.setEnabled(False)\n\n    def sendMotionDownsampleAction(self):\n        value = self.motionDownsampleEdit.text()\n        value = value.replace(',', '.')\n        self.motionDownsampleEdit.setText(value)\n        self.device.sendMotionDownsample(value)\n\n    def sendCurrentLimitAction(self):\n        value = self.clLineEdit.text()\n        value = value.replace(',', '.')\n        self.clLineEdit.setText(value)\n        self.device.sendCurrentLimit(self.clLineEdit.text())\n\n    def sendVelLimitAction(self):\n        value = self.vlLineEdit.text()\n        value = value.replace(',', '.')\n        self.vlLineEdit.setText(value)\n        self.device.sendVelocityLimit(self.vlLineEdit.text())\n\n    def sendVoltageLimitAction(self):\n        value = self.volLLineEdit.text()\n        value = value.replace(',', '.')\n        self.volLLineEdit.setText(value)\n        self.device.sendVoltageLimit(self.volLLineEdit.text())\n\n    def commandResponseReceived(self, comandResponse):\n        self.reloadValues()\n        \n    def reloadValues(self):\n        self.motionDownsampleEdit.setText(str(self.device.motionDownsample))\n        self.clLineEdit.setText(str(self.device.currentLimit))\n        self.vlLineEdit.setText(str(self.device.velocityLimit))\n        self.volLLineEdit.setText(str(self.device.voltageLimit))"
  },
  {
    "path": "src/gui/configtool/generatedCodeDisplay.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom PyQt5 import QtWidgets\nfrom PyQt5.QtCore import QRegExp\nfrom PyQt5.QtCore import Qt\nfrom PyQt5.QtGui import (QSyntaxHighlighter,QTextCharFormat,QBrush,QColor)\nfrom PyQt5.QtWidgets import (QVBoxLayout)\n\nfrom src.gui.sharedcomnponets.sharedcomponets import (WorkAreaTabWidget,\n                                                      GUIToolKit)\nfrom src.simpleFOCConnector import SimpleFOCDevice\n\n\nclass GenerateCodeDialog(QtWidgets.QDialog):\n    def __init__(self, parent=None):\n        super().__init__(parent=parent)\n        self.setWindowTitle(\"Generate Code\")\n        self.setWindowIcon(GUIToolKit.getIconByName('gen'))\n\n        self.checkBoxMotionControl = QtWidgets.QCheckBox(self)\n        self.checkBoxMotionControl.setObjectName('motion')\n        self.checkBoxMotionControl.setText(\"Torque/Motion control\")\n        self.checkBoxMotionControl.setIcon(GUIToolKit.getIconByName('motor'))\n        self.checkBoxMotionControl.setChecked(True)\n\n        self.checkBoxPidVel = QtWidgets.QCheckBox(self)\n        self.checkBoxPidVel.setObjectName('pidVel')\n        self.checkBoxPidVel.setText(\"PID velocity\")\n        self.checkBoxPidVel.setIcon(GUIToolKit.getIconByName('pidconfig'))\n        self.checkBoxPidVel.setChecked(True)\n        \n        self.checkBoxPidAngle = QtWidgets.QCheckBox(self)\n        self.checkBoxPidAngle.setObjectName('pidAngle')\n        self.checkBoxPidAngle.setText(\"PID angle\")\n        self.checkBoxPidAngle.setIcon(GUIToolKit.getIconByName('pidconfig'))\n        self.checkBoxPidAngle.setChecked(True)\n        \n        self.checkBoxPidCq = QtWidgets.QCheckBox(self)\n        self.checkBoxPidCq.setObjectName('pidCq')\n        self.checkBoxPidCq.setText(\"PID current q\")\n        self.checkBoxPidCq.setIcon(GUIToolKit.getIconByName('pidconfig'))\n        self.checkBoxPidCq.setChecked(True)\n        \n        self.checkBoxPidCd = QtWidgets.QCheckBox(self)\n        self.checkBoxPidCd.setObjectName('pidCq')\n        self.checkBoxPidCd.setText(\"PID current d\")\n        self.checkBoxPidCd.setIcon(GUIToolKit.getIconByName('pidconfig'))\n        self.checkBoxPidCd.setChecked(True)\n        \n        self.checkBoxLimits = QtWidgets.QCheckBox(self)\n        self.checkBoxLimits.setObjectName('limits')\n        self.checkBoxLimits.setText(\"Limits\")\n        self.checkBoxLimits.setIcon(GUIToolKit.getIconByName('statistics'))\n        self.checkBoxLimits.setChecked(True)\n        \n        self.checkBoxPhaseRes = QtWidgets.QCheckBox(self)\n        self.checkBoxPhaseRes.setObjectName('phaseRes')\n        self.checkBoxPhaseRes.setText(\"Phase Resistance\")\n        self.checkBoxPhaseRes.setIcon(GUIToolKit.getIconByName('res'))\n        self.checkBoxPhaseRes.setChecked(True)\n        \n        self.checkBoxModulation = QtWidgets.QCheckBox(self)\n        self.checkBoxModulation.setObjectName('modulation')\n        self.checkBoxModulation.setText(\"PWM Modulation\")\n        self.checkBoxModulation.setIcon(GUIToolKit.getIconByName('gear'))\n        self.checkBoxModulation.setChecked(True)\n        \n        self.sensorOffset = QtWidgets.QCheckBox(self)\n        self.sensorOffset.setObjectName('sensorOffset')\n        self.sensorOffset.setText(\"Sensor Offset\")\n        self.sensorOffset.setIcon(GUIToolKit.getIconByName('gear'))\n        self.sensorOffset.setChecked(True)\n\n        self.sensorElOffset = QtWidgets.QCheckBox(self)\n        self.sensorElOffset.setObjectName('sensorOffset')\n        self.sensorElOffset.setToolTip('Be careful!<br> Only for absolute sensors')\n        self.sensorElOffset.setText(\"Sensor Electrical Offset\")\n        self.sensorElOffset.setIcon(GUIToolKit.getIconByName('gear'))\n        self.sensorElOffset.setChecked(False)\n\n        QBtn = QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel\n\n        self.buttonBox = QtWidgets.QDialogButtonBox(QBtn)\n        self.buttonBox.accepted.connect(self.accept)\n        self.buttonBox.rejected.connect(self.reject)\n\n        text = \"<h1>Arduino Code Generation</h1>\"\n        text += \"Arduino code generation for the motor parameters currently used in the <i>Simple<b>FOC</b>Studio</i> <br>\"\n        text += \"Once you are happy with the performance of your system you can generate the arduino code of the parameters you have tuned.<br>\"\n        text += \"The generated code you can just copy/paste in your <code>setup()</code> function, just before calling the <code>motor.init()</code><br>\"\n        text += \"<h4>Choose the parameter sets to be generated:</h4>\"\n\n        self.layout = QtWidgets.QVBoxLayout()\n        message1 = QtWidgets.QLabel(text)\n        self.layout.addWidget(message1)\n        self.layout.addWidget(self.checkBoxMotionControl)\n        self.layout.addWidget(self.checkBoxPidVel)\n        self.layout.addWidget(self.checkBoxPidAngle)\n        self.layout.addWidget(self.checkBoxPidCq)\n        self.layout.addWidget(self.checkBoxPidCd)\n        self.layout.addWidget(self.checkBoxLimits)\n        self.layout.addWidget(self.checkBoxPhaseRes)\n        self.layout.addWidget(self.checkBoxModulation)\n        self.layout.addWidget(self.sensorOffset)\n        self.layout.addWidget(self.sensorElOffset)\n        self.layout.addWidget(self.buttonBox)\n        self.setLayout(self.layout)\n\nclass GeneratedCodeDisplay(WorkAreaTabWidget):\n\n    def __init__(self, parent=None ):\n        super().__init__(parent)\n        \n        self.device = SimpleFOCDevice.getInstance()\n        dlg = GenerateCodeDialog()  # If you pass self, the dialog will be centered over the main window as before.\n        if dlg.exec_():\n            toGenerate=[\n                dlg.checkBoxMotionControl.isChecked(),\n                dlg.checkBoxPidVel.isChecked(),\n                dlg.checkBoxPidAngle.isChecked(),\n                dlg.checkBoxPidCq.isChecked(),\n                dlg.checkBoxPidCd.isChecked(),\n                dlg.checkBoxLimits.isChecked(),\n                dlg.sensorOffset.isChecked(),\n                dlg.sensorElOffset.isChecked(),\n                dlg.checkBoxPhaseRes.isChecked(),\n                dlg.checkBoxModulation.isChecked(),\n            ]\n            code = self.device.toArduinoCode(toGenerate)\n\n        self.layout = QVBoxLayout(self)\n\n        text = \"<h1>Generated Arduino Code</h1>\"\n        text += \"This generated code you can just copy/paste into your <code>setup()</code> function, it is important that you place it before calling the <code>motor.init()</code><br>\"\n\n        message1 = QtWidgets.QLabel(text)\n        self.layout.addWidget(message1)\n\n        self.codeDisplayBefore = QtWidgets.QLabel(self)\n        self.layout.addWidget(self.codeDisplayBefore)\n        code0 = '<font color=\"#5e6d03\">#include</font> <font color=\"#434f54\">&lt;</font><b><font color=\"#d35400\">SimpleFOC</font></b><font color=\"#434f54\">.</font><font color=\"#000000\">h</font><font color=\"#434f54\">&gt;</font>'\n        code0 +=\"<br>...<br>\"\n        code0 += '<font color=\"#00979c\">void</font> <font color=\"#5e6d03\">setup</font><font color=\"#000000\">(</font><font color=\"#000000\">)</font> <font color=\"#000000\">{</font><br>'\n        code0 += \"  ....\"\n        self.codeDisplayBefore.setText(code0)\n        self.codeDisplayBefore.setTextFormat(Qt.TextFormat.RichText)\n\n        self.codeDisplay = QtWidgets.QTextEdit(self)\n        self.codeDisplay.setObjectName('codeDisplay')\n        self.codeDisplay.setText(code)\n\n        highlighter = MyHighlighter( self.codeDisplay, \"Classic\" )\n        self.layout.addWidget(self.codeDisplay)\n\n        self.codeDisplayAfter = QtWidgets.QLabel(self)\n        self.layout.addWidget(self.codeDisplayAfter)\n        code1 = '<font color=\"#434f54\">&#47;&#47; initialize motor</font><br>'\n        code1 += '<font color=\"#d35400\">motor</font><font color=\"#434f54\">.</font><font color=\"#d35400\">init</font><font color=\"#000000\">(</font><font color=\"#000000\">)</font><font color=\"#000000\">;</font><br>'\n        code1 += '<font color=\"#434f54\">&#47;&#47; align sensor and start FOC</font><br>'\n        code1 += '<font color=\"#d35400\">motor</font><font color=\"#434f54\">.</font><font color=\"#d35400\">initFOC</font><font color=\"#000000\">(</font><font color=\"#000000\">)</font><font color=\"#000000\">;</font><br> ...<br> }'\n        code1 += '<br><font color=\"#00979c\">void</font> <font color=\"#5e6d03\">loop</font><font color=\"#000000\">(</font><font color=\"#000000\">)</font> <font color=\"#000000\">{</font>'\n        code1 += '<br> .... <br>'\n        code1 += '<font color=\"#d35400\">motor</font><font color=\"#434f54\">.</font><font color=\"#d35400\">move</font><font color=\"#000000\">(</font><font color=\"#000000\">)</font><font color=\"#000000\">;</font><br>'\n        code1 += '<font color=\"#d35400\">motor</font><font color=\"#434f54\">.</font><font color=\"#d35400\">loopFOC</font><font color=\"#000000\">(</font><font color=\"#000000\">)</font><font color=\"#000000\">;</font><br>'\n        code1 += '.... <br>}'\n        # MyHighlighter( self.codeDisplayAfter, \"Classic\" )\n        self.codeDisplayAfter.setText(code1)\n        self.codeDisplayAfter.setTextFormat(Qt.TextFormat.RichText)\n\n        self.setLayout(self.layout)\n\n    def getTabIcon(self):\n        return GUIToolKit.getIconByName('gen')\n\n    def getTabName(self):\n        return 'Generated Code'\n\n\nclass MyHighlighter( QSyntaxHighlighter ):\n\n    def __init__( self, parent, theme ):\n      QSyntaxHighlighter.__init__( self, parent )\n      self.parent = parent\n      keyword = QTextCharFormat()\n      comment = QTextCharFormat()\n\n      self.highlightingRules = []\n\n      # keyword\n      brush = QBrush(QColor(211,84,0), Qt.SolidPattern )\n      keyword.setForeground( brush )\n      keywords = list( [ \"motor\",'FOCModulationType','MotionControlType','TorqueControlType'] )\n      for word in keywords:\n        pattern = QRegExp(\"\\\\b\" + word + \"\\\\b\")\n        rule = HighlightingRule( pattern, keyword )\n        self.highlightingRules.append( rule )\n\n      # comment\n      brush = QBrush( Qt.gray, Qt.SolidPattern )\n      pattern = QRegExp( \"\\/\\/.*[^\\n]\" )\n      comment.setForeground( brush )\n      comment.setFontItalic( True )\n      rule = HighlightingRule( pattern, comment )\n      self.highlightingRules.append( rule )\n\n\n    def highlightBlock( self, text ):\n      for rule in self.highlightingRules:\n        expression = QRegExp( rule.pattern )\n        index = expression.indexIn( text )\n        while index >= 0:\n          length = expression.matchedLength()\n          self.setFormat( index, length, rule.format )\n          index = expression.indexIn( text, index + length )\n      self.setCurrentBlockState( 0 )\n\nclass HighlightingRule():\n  def __init__( self, pattern, format ):\n    self.pattern = pattern\n    self.format = format\n"
  },
  {
    "path": "src/gui/configtool/graphicWidget.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nimport logging\n\nimport numpy as np\nimport pyqtgraph as pg\nfrom PyQt5 import QtWidgets\n\nfrom src.gui.sharedcomnponets.sharedcomponets import GUIToolKit\nfrom src.simpleFOCConnector import SimpleFOCDevice\n\nclass SimpleFOCGraphicWidget(QtWidgets.QGroupBox):\n\n    disconnectedState = 0\n    initialConnectedState = 1\n    connectedPausedState = 2\n    connectedPlottingStartedState = 3\n\n    signals = ['Target', 'Vq','Vd','Cq','Cd','Vel','Angle']\n    signal_tooltip = ['Target', 'Voltage Q [Volts]','Voltage D [Volts]','Current Q [miliAmps]','Current D [miliAmps]','Velocity [rad/sec]','Angle [rad]']\n    signalColors = [GUIToolKit.RED_COLOR, GUIToolKit.BLUE_COLOR, GUIToolKit.PURPLE_COLOR,GUIToolKit.YELLOW_COLOR, GUIToolKit.MAROON_COLOR, GUIToolKit.ORANGE_COLOR, GUIToolKit.GREEN_COLOR]\n    signalIcons = ['reddot', 'bluedot','purpledot', 'yellowdot', 'maroondot', 'orangedot', 'greendot']\n\n    def __init__(self, parent=None):\n\n        super().__init__(parent)\n\n        self.setObjectName('plotWidget')\n        self.setTitle('Real time motor variables: ')\n        self.horizontalLayout = QtWidgets.QVBoxLayout(self)\n        self.device = SimpleFOCDevice.getInstance()\n\n        self.numberOfSamples = 300\n\n        pg.setConfigOptions(antialias=True)\n        self.plotWidget = pg.PlotWidget()\n        self.plotWidget.showGrid(x=True, y=True, alpha=0.5)\n        self.plotWidget.addLegend()\n\n        # self.legend = pg.LegendItem()\n        # self.legend.setParentItem(self.plotWidget)\n\n        self.timeArray = np.arange(-self.numberOfSamples, 0, 1)\n        \n        self.controlPlotWidget = ControlPlotPanel(controllerPlotWidget=self)\n\n        self.signalDataArrays = []\n        self.signalPlots = []\n        self.signalPlotFlags = []\n        for (sig, sigColor, checkBox, tooltip) in zip(self.signals, self.signalColors,self.controlPlotWidget.signalCheckBox, self.signal_tooltip):\n            # define signal plot data array\n            self.signalDataArrays.append(np.zeros(self.numberOfSamples))\n            # configure signal plot parameters\n            signalPen = pg.mkPen(color=sigColor, width=1.5)\n            self.signalPlots.append(pg.PlotDataItem(self.timeArray,\n                                            self.signalDataArrays[-1],\n                                            pen=signalPen, name=tooltip))\n            self.plotWidget.addItem(self.signalPlots[-1])\n\n            # is plotted flag\n            self.signalPlotFlags.append(True)\n            # add callback\n            checkBox.stateChanged.connect(self.signalPlotFlagUpdate)\n\n        self.horizontalLayout.addWidget(self.plotWidget)\n        self.horizontalLayout.addWidget(self.controlPlotWidget)\n        \n        self.device.commProvider.monitoringDataReceived.connect(\n            self.upDateGraphic)\n\n        self.currentStatus = self.disconnectedState\n        self.controlPlotWidget.pauseContinueButton.setDisabled(True)\n\n        self.device.addConnectionStateListener(self)\n\n        self.connectionStateChanged(self.device.isConnected)\n\n    def connectionStateChanged(self, deviceConnected):\n        if deviceConnected is True:\n            self.currentStatus = self.initialConnectedState\n            self.enabeUI()\n        else:\n            self.controlPlotWidget.startStoPlotAction()\n            self.controlPlotWidget.stopAndResetPlot()\n            self.currentStatus = self.disconnectedState\n            self.disableUI()\n\n    def enabeUI(self):\n        self.setEnabled(True)\n\n    def disableUI(self):\n        self.setEnabled(False)\n\n    def signalPlotFlagUpdate(self):\n        self.controlPlotWidget.updateMonitorVariables()\n        for i, (checkBox, plotFlag) in enumerate(zip(self.controlPlotWidget.signalCheckBox, self.signalPlotFlags)):\n            if checkBox.isChecked() and (not plotFlag):\n                self.signalPlotFlags[i] = True\n                self.plotWidget.addItem( self.signalPlots[i] )\n            elif (not checkBox.isChecked()) and plotFlag:\n                self.signalPlotFlags[i]  = False\n                self.plotWidget.removeItem( self.signalPlots[i] )\n\n    def connectioStatusUpdate(self, connectedFlag):\n        if connectedFlag:\n            self.currentStatus = self.initialConnectedState\n        else:\n            self.currentStatus = self.disconnectedState\n\n    def upDateGraphic(self, signalList):\n        if self.currentStatus is self.connectedPlottingStartedState or \\\n                self.currentStatus is self.connectedPausedState:\n\n            signals = np.array(signalList, dtype=float)\n            signalIndex = 0\n\n            enabled = np.where(np.array(self.signalPlotFlags) == True)[0]\n\n            if(len(enabled) != len(signals)):\n                logging.warning('Arrived corrupted data')\n                return\n            else:\n                for i, ind in enumerate(enabled):\n                    self.signalDataArrays[ind] = np.roll(self.signalDataArrays[ind], -1)\n                    self.signalDataArrays[ind][-1] = signals[i]\n\n            if self.currentStatus is self.connectedPlottingStartedState:\n                self.updatePlot()\n\n\n    def computeStatic(self, array):\n        mean = np.mean(array)\n        std = np.std(array)\n        max = np.max(array)\n        min = np.min(array)\n        meadian = np.median(array)\n\n    def updatePlot(self):\n        for i, plotFlag in enumerate(self.signalPlotFlags):\n            if plotFlag:\n                self.signalPlots[i].setData(self.timeArray, self.signalDataArrays[i])\n                self.signalPlots[i].updateItems()\n                self.signalPlots[i].sigPlotChanged.emit(self.signalPlots[i])\n\n\nclass ControlPlotPanel(QtWidgets.QWidget):\n\n    def __init__(self, parent=None, controllerPlotWidget=None):\n        '''Constructor for ToolsWidget'''\n        super().__init__(parent)\n\n        self.device = SimpleFOCDevice.getInstance()\n        self.controlledPlot = controllerPlotWidget\n        \n        self.verticalLayout = QtWidgets.QVBoxLayout(self)\n        self.setLayout(self.verticalLayout)\n\n        self.horizontalLayout1 = QtWidgets.QHBoxLayout()\n        self.horizontalLayout1.setObjectName('horizontalLayout')\n\n        self.startStopButton = QtWidgets.QPushButton(self)\n        self.startStopButton.setText('Start')\n        self.startStopButton.setObjectName('Start')\n        self.startStopButton.clicked.connect(self.startStoPlotAction)\n        self.startStopButton.setIcon(GUIToolKit.getIconByName('start'))\n        self.horizontalLayout1.addWidget(self.startStopButton)\n\n        self.pauseContinueButton = QtWidgets.QPushButton(self)\n        self.pauseContinueButton.setObjectName('pauseButton')\n        self.pauseContinueButton.setText('Pause')\n        self.pauseContinueButton.setIcon(GUIToolKit.getIconByName('pause'))\n        self.pauseContinueButton.clicked.connect(self.pauseContinuePlotAction)\n        self.horizontalLayout1.addWidget(self.pauseContinueButton)\n\n        self.zoomAllButton = QtWidgets.QPushButton(self)\n        self.zoomAllButton.setObjectName('zoomAllButton')\n        self.zoomAllButton.setText('View all')\n        self.zoomAllButton.setIcon(GUIToolKit.getIconByName('zoomall'))\n        self.zoomAllButton.clicked.connect(self.zoomAllPlot)\n        self.horizontalLayout1.addWidget(self.zoomAllButton)\n\n        self.signalCheckBox = []\n        for i in range(len(self.controlledPlot.signals)):\n            checkBox = QtWidgets.QCheckBox(self)\n            checkBox.setObjectName('signalCheckBox'+str(i))\n            checkBox.setToolTip(self.controlledPlot.signal_tooltip[i])\n            checkBox.setText(self.controlledPlot.signals[i])\n            checkBox.setIcon(GUIToolKit.getIconByName(self.controlledPlot.signalIcons[i]))\n            checkBox.setChecked(True)\n            self.signalCheckBox.append(checkBox)\n            self.horizontalLayout1.addWidget(checkBox)\n\n\n        spacerItem = QtWidgets.QSpacerItem(100, 20,\n                                           QtWidgets.QSizePolicy.Expanding,\n                                           QtWidgets.QSizePolicy.Maximum)\n\n        self.horizontalLayout1.addItem(spacerItem)\n        self.horizontalLayout1.addItem(spacerItem)\n\n        self.downsampleLabel = QtWidgets.QLabel(self)\n        self.downsampleLabel.setText('Downsample')\n        self.downampleValue = QtWidgets.QLineEdit(self.downsampleLabel)\n        self.downampleValue.setText(\"100\")\n        self.downampleValue.editingFinished.connect(self.changeDownsampling)\n        self.horizontalLayout1.addWidget(self.downsampleLabel)\n        self.horizontalLayout1.addWidget(self.downampleValue)\n\n        self.verticalLayout.addLayout(self.horizontalLayout1)\n\n    def startStoPlotAction(self):\n        if self.controlledPlot.currentStatus is self.controlledPlot.initialConnectedState:\n            # Start pressed\n            self.startStopButton.setText('Stop')\n            self.startStopButton.setIcon(GUIToolKit.getIconByName('stop'))\n            self.controlledPlot.currentStatus = \\\n                self.controlledPlot.connectedPlottingStartedState\n            self.pauseContinueButton.setEnabled(True)\n            self.device.sendMonitorDownsample(int(self.downampleValue.text()))\n            self.updateMonitorVariables()\n        else:\n            # Stop pressed\n            self.startStopButton.setText('Start')\n            self.startStopButton.setIcon(GUIToolKit.getIconByName('start'))\n            self.pauseContinueButton.setText('Pause')\n            self.pauseContinueButton.setIcon(GUIToolKit.getIconByName('pause'))\n            self.pauseContinueButton.setEnabled(False)\n            self.stopAndResetPlot()\n            self.device.sendMonitorDownsample(0)\n            self.device.sendMonitorClearVariables()\n\n    def pauseContinuePlotAction(self):\n        if self.controlledPlot.currentStatus is self.controlledPlot.connectedPausedState:\n            # Continue pressed\n            self.pauseContinueButton.setText('Pause')\n            self.pauseContinueButton.setIcon(GUIToolKit.getIconByName('pause'))\n            self.controlledPlot.currentStatus = self.controlledPlot.connectedPlottingStartedState\n        else:\n            # Pause pressed\n            self.pauseContinueButton.setText('Continue')\n            self.pauseContinueButton.setIcon(\n                GUIToolKit.getIconByName('continue'))\n            self.controlledPlot.currentStatus = self.controlledPlot.connectedPausedState\n\n    def stopAndResetPlot(self):\n        self.controlledPlot.currentStatus = self.controlledPlot.initialConnectedState\n        for dataArray in self.controlledPlot.signalDataArrays:\n            dataArray = np.zeros(self.controlledPlot.numberOfSamples)\n\n    def zoomAllPlot(self):\n        self.controlledPlot.plotWidget.enableAutoRange()\n\n    def changeDownsampling(self):\n        if  self.controlledPlot.currentStatus == self.controlledPlot.connectedPlottingStartedState:\n            self.device.sendMonitorDownsample(int(self.downampleValue.text()))\n\n    def updateMonitorVariables(self):\n        self.device.sendMonitorVariables([self.signalCheckBox[0].isChecked(), \n                                                self.signalCheckBox[1].isChecked(),\n                                                 self.signalCheckBox[2].isChecked(), \n                                                 self.signalCheckBox[3].isChecked(), \n                                                 self.signalCheckBox[4].isChecked(), \n                                                 self.signalCheckBox[5].isChecked(), \n                                                 self.signalCheckBox[6].isChecked()])\n"
  },
  {
    "path": "src/gui/configtool/pidConfiguration.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom PyQt5 import (QtGui, QtWidgets, QtCore)\nfrom src.gui.sharedcomnponets.sharedcomponets import ConfigQLineEdit\nfrom src.simpleFOCConnector import SimpleFOCDevice\n\n\nclass PidGroupBox(QtWidgets.QGroupBox):\n\n    def __init__(self, parent=None):\n\n        super().__init__(parent)\n        self.setMaximumWidth(300)\n\n        onlyFloatInputValidator = QtGui.QRegExpValidator(\n            QtCore.QRegExp(\"[+-]?([0-9]*[.])?[0-9]+\"))\n\n        self.device = SimpleFOCDevice.getInstance()\n\n            \n        self.activePID = self.device.PIDVelocity\n        self.activeLPF = self.device.LPFVelocity\n\n        self.setObjectName('pidConfigurator')\n        self.setTitle('PID Controller configuration')\n\n        self.gridLayout = QtWidgets.QGridLayout(self)\n        self.gridLayout.setObjectName('gridLayout')\n        \n        self.sPidLabel = QtWidgets.QLabel(self)\n        self.sPidLabel.setObjectName('pgLabel')\n        self.sPidLabel.setText('Select PID')\n        self.gridLayout.addWidget(self.sPidLabel, 0, 1, 1, 1)\n\n        self.selectorPIDF = QtWidgets.QComboBox(self)\n        self.selectorPIDF.setObjectName('selectPIDF')\n        self.selectorPIDF.addItems(['Velocity', 'Angle', 'Current Q', 'Current D'])\n        self.selectorPIDF.currentIndexChanged.connect(self.changePIDF)\n        self.gridLayout.addWidget(self.selectorPIDF, 0, 2, 1, 1)\n\n        self.pgLabel = QtWidgets.QLabel(self)\n        self.pgLabel.setObjectName('pgLabel')\n        self.pgLabel.setText('Proportional gain')\n        self.gridLayout.addWidget(self.pgLabel, 1, 1, 1, 1)\n\n        self.iglabel = QtWidgets.QLabel(self)\n        self.iglabel.setObjectName('iglabel')\n        self.iglabel.setText('Integral gain')\n        self.gridLayout.addWidget(self.iglabel, 2, 1, 1, 1)\n\n        self.dgLabel = QtWidgets.QLabel(self)\n        self.dgLabel.setObjectName('dgLabel')\n        self.dgLabel.setText('Derivative gain')\n        self.gridLayout.addWidget(self.dgLabel, 3, 1, 1, 1)\n\n        self.vrLabel = QtWidgets.QLabel(self)\n        self.vrLabel.setObjectName('vrLabel')\n        self.vrLabel.setText('Output ramp')\n        self.gridLayout.addWidget(self.vrLabel, 4, 1, 1, 1)\n\n        self.vrLabel = QtWidgets.QLabel(self)\n        self.vrLabel.setObjectName('lpfLabel')\n        self.vrLabel.setText('Low pass filter')\n        self.gridLayout.addWidget(self.vrLabel, 5, 1, 1, 1)\n\n        self.pgLineEdit = ConfigQLineEdit(self)\n        self.pgLineEdit.setObjectName('pgLineEdit')\n        self.pgLineEdit.setValidator(onlyFloatInputValidator)\n        self.pgLineEdit.setAlignment(QtCore.Qt.AlignCenter)\n        self.pgLineEdit.editingFinished.connect(self.sendProportionalGainAction)\n        self.gridLayout.addWidget(self.pgLineEdit, 1, 2, 1, 1)\n\n        self.igLineEdit = ConfigQLineEdit(self)\n        self.igLineEdit.setObjectName('igLineEdit')\n        self.igLineEdit.setValidator(onlyFloatInputValidator)\n        self.igLineEdit.setAlignment(QtCore.Qt.AlignCenter)\n        self.igLineEdit.editingFinished.connect(self.sendIntegralGainAction)\n        self.gridLayout.addWidget(self.igLineEdit, 2, 2, 1, 1)\n\n        self.dgLineEdit = ConfigQLineEdit(self)\n        self.dgLineEdit.setObjectName('dgLineEdit')\n        self.dgLineEdit.setValidator(onlyFloatInputValidator)\n        self.dgLineEdit.setAlignment(QtCore.Qt.AlignCenter)\n        self.dgLineEdit.editingFinished.connect(self.sendDerivativeGainAction)\n        self.gridLayout.addWidget(self.dgLineEdit, 3, 2, 1, 1)\n        \n        self.vrLineEdit = ConfigQLineEdit(self)\n        self.vrLineEdit.setObjectName('vrLineEdit')\n        self.vrLineEdit.setValidator(onlyFloatInputValidator)\n        self.vrLineEdit.setAlignment(QtCore.Qt.AlignCenter)\n        self.vrLineEdit.editingFinished.connect(self.sendRampAction)\n        self.gridLayout.addWidget(self.vrLineEdit, 4, 2, 1, 1)\n\n        self.lpfLineEdit = ConfigQLineEdit(self)\n        self.lpfLineEdit.setObjectName('lpfLineEdit')\n        self.lpfLineEdit.setValidator(onlyFloatInputValidator)\n        self.lpfLineEdit.setAlignment(QtCore.Qt.AlignCenter)\n        self.lpfLineEdit.editingFinished.connect(self.sendLPFAction)\n        self.gridLayout.addWidget(self.lpfLineEdit, 5, 2, 1, 1)\n\n        self.reloadPIDValues()\n\n        # self.setDerivativeGainAction(self.device.derivativeGainPID)\n        # self.setProportionalGainAction(self.device.proportionalGainPID)\n        # self.setIntegralGainAction(self.device.integralGainPID)\n        # self.setVoltageRampAction(self.device.voltageRampPID)\n\n        self.connectionStateChanged(self.device.isConnected)\n        self.device.addConnectionStateListener(self)\n        self.device.commProvider.commandDataReceived.connect(self.commandResponseReceived)\n\n    def connectionStateChanged(self, deviceConnected):\n        if deviceConnected is True:\n            self.enabeUI()\n        else:\n            self.disableUI()\n\n    def enabeUI(self):\n        self.setEnabled(True)\n\n    def disableUI(self):\n        self.setEnabled(False)\n\n    def sendDerivativeGainAction(self):\n        value = self.dgLineEdit.text()\n        value = value.replace(',', '.')\n        self.dgLineEdit.setText(value)\n        self.device.sendDerivativeGain(self.activePID, value)\n\n    def sendProportionalGainAction(self):\n        value = self.pgLineEdit.text()\n        value = value.replace(',', '.')\n        self.pgLineEdit.setText(value)\n        self.device.sendProportionalGain(self.activePID, self.pgLineEdit.text())\n\n    def sendIntegralGainAction(self):\n        value = self.igLineEdit.text()\n        value = value.replace(',', '.')\n        self.igLineEdit.setText(value)\n        self.device.sendIntegralGain(self.activePID, self.igLineEdit.text())\n\n    def sendRampAction(self):\n        value = self.vrLineEdit.text()\n        value = value.replace(',', '.')\n        self.vrLineEdit.setText(value)\n        self.device.sendOutputRamp(self.activePID, self.vrLineEdit.text())\n\n    def sendLPFAction(self):\n        value = self.lpfLineEdit.text()\n        value = value.replace(',', '.')\n        self.lpfLineEdit.setText(value)\n        self.device.sendLowPassFilter(self.activeLPF, self.lpfLineEdit.text())\n\n    def reloadPIDValues(self):\n        self.pgLineEdit.setText(str(self.activePID.P))\n        self.dgLineEdit.setText(str(self.activePID.D))\n        self.igLineEdit.setText(str(self.activePID.I))\n        self.vrLineEdit.setText(str(self.activePID.outputRamp))\n        self.lpfLineEdit.setText(str(self.activeLPF.Tf))\n\n    def changePIDF(self):\n        index = self.selectorPIDF.currentIndex()\n        if index == 0:\n            self.activePID = self.device.PIDVelocity\n            self.activeLPF = self.device.LPFVelocity\n        elif index == 1:\n            self.activePID = self.device.PIDAngle\n            self.activeLPF = self.device.LPFAngle\n        elif index == 2:\n            self.activePID = self.device.PIDCurrentQ\n            self.activeLPF = self.device.LPFCurrentQ\n        elif index == 3:\n            self.activePID = self.device.PIDCurrentD\n            self.activeLPF = self.device.LPFCurrentD\n\n        self.device.pullPIDConf(self.activePID, self.activeLPF)\n        self.reloadPIDValues()\n\n    def commandResponseReceived(self, commandDataReceived):\n        self.pgLineEdit.setText(str(self.activePID.P))\n        self.dgLineEdit.setText(str(self.activePID.D))\n        self.igLineEdit.setText(str(self.activePID.I))\n        self.vrLineEdit.setText(str(self.activePID.outputRamp))\n        self.lpfLineEdit.setText(str(self.activeLPF.Tf))\n\n"
  },
  {
    "path": "src/gui/configtool/torqueConfig.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom PyQt5 import QtWidgets\n\nfrom src.simpleFOCConnector import SimpleFOCDevice\n\n\nclass TorqueGroupBox(QtWidgets.QGroupBox):\n    def __init__(self, parent=None):\n        super().__init__(parent)\n\n        self.device = SimpleFOCDevice.getInstance()\n\n        self.setObjectName('torqueMode')\n        self.setTitle('Torque Mode')\n        \n        self.torqueTypeHorizontalLayout = QtWidgets.QHBoxLayout(self)\n        self.torqueTypeHorizontalLayout.setObjectName('torqueHorizontalLayout')\n\n\n        \n        self.selectorTorque = QtWidgets.QComboBox(self)\n        self.selectorTorque.setObjectName('selectorControlLoop')\n        self.selectorTorque.addItems(['Voltage', 'DC Current', 'FOC Current'])\n        self.selectorTorque.currentIndexChanged.connect(self.changeTorque)\n        self.torqueTypeHorizontalLayout.addWidget(self.selectorTorque)\n\n        self.setTorqueMode(self.device.torqueType)\n\n        self.disableUI()\n        self.device.addConnectionStateListener(self)\n        self.device.commProvider.commandDataReceived.connect(\n            self.commandResponseReceived)\n\n        self.connectionStateChanged(self.device.isConnected)\n\n    def connectionStateChanged(self, deviceConnected):\n        if deviceConnected is True:\n            self.enabeUI()\n        else:\n            self.disableUI()\n\n    def enabeUI(self):\n        self.setEnabled(True)\n\n    def disableUI(self):\n        self.setEnabled(False)\n\n    def setTorqueMode(self, value):\n        if value == SimpleFOCDevice.VOLTAGE_TORQUE:\n            self.selectorTorque.setCurrentIndex(0)\n        elif value == SimpleFOCDevice.DC_CURRENT_TORQUE:\n            self.selectorTorque.setCurrentIndex(1)\n        elif value == SimpleFOCDevice.FOC_CURRENT_TORQUE:\n            self.selectorTorque.setCurrentIndex(2)\n\n    def changeTorque(self):\n        index = self.selectorTorque.currentIndex()\n        if index == 0:\n            self.device.sendTorqueType(SimpleFOCDevice.VOLTAGE_TORQUE)\n        elif index == 1:\n            self.device.sendTorqueType(SimpleFOCDevice.DC_CURRENT_TORQUE)\n        elif index == 2:\n            self.device.sendTorqueType(SimpleFOCDevice.FOC_CURRENT_TORQUE)\n\n    def commandResponseReceived(self, cmdRespose):\n        self.setTorqueMode(self.device.torqueType)"
  },
  {
    "path": "src/gui/configtool/treeViewConfigTool.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom PyQt5.QtCore import Qt\nfrom PyQt5.QtWidgets import (QVBoxLayout, QSplitter)\n\nfrom src.gui.configtool.deviceInteractionFrame import DeviceInteractionFrame\nfrom src.gui.configtool.devicesInspectorTree import DevicesInspectorTree\nfrom src.gui.sharedcomnponets.sharedcomponets import (WorkAreaTabWidget,\n                                                      GUIToolKit)\nfrom src.simpleFOCConnector import SimpleFOCDevice\n\n\nclass TreeViewConfigTool(WorkAreaTabWidget):\n\n    def __init__(self, parent=None):\n        super().__init__(parent)\n        self.device = SimpleFOCDevice.getInstance()\n\n        self.layout = QVBoxLayout(self)\n\n        self.treeViewWidget = DevicesInspectorTree(self)\n        self.leftWidget = DeviceInteractionFrame(self)\n\n        self.verticalSplitter = QSplitter(Qt.Horizontal)\n        self.verticalSplitter.addWidget(self.treeViewWidget)\n        self.verticalSplitter.addWidget(self.leftWidget)\n\n        self.layout.addWidget(self.verticalSplitter)\n\n        self.setLayout(self.layout)\n\n    def getTabIcon(self):\n        return GUIToolKit.getIconByName('motor')\n\n    def getTabName(self):\n        return self.device.connectionID"
  },
  {
    "path": "src/gui/mainWindow.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom PyQt5 import (QtCore, QtWidgets)\n\nfrom src.gui.toolbar import SimpleFOCConfigToolBar\nfrom src.gui.workAreaTabbedWidget import WorkAreaTabbedWidget\n\n\nclass UserInteractionMainWindow(object):\n\n    def setupUi(self, main_window):\n\n        main_window.setObjectName('MainWindow')\n        main_window.resize(1300, 900)\n        main_window.setWindowTitle('SimpleFOC Configuration Tool ')\n\n        self.centralwidget = QtWidgets.QWidget(main_window)\n        self.centralwidget.setObjectName('centralwidget')\n\n        # Add layout de to the main window\n        self.horizontalLayout = QtWidgets.QVBoxLayout(self.centralwidget)\n        self.horizontalLayout.setObjectName('verticalLayout')\n\n        # Add tabebd tools widget to the main  window\n        self.tabbedToolsWidget = WorkAreaTabbedWidget(self.centralwidget)\n        self.horizontalLayout.addWidget(self.tabbedToolsWidget)\n\n        # Add toolbar to the main window\n        self.toolBar = SimpleFOCConfigToolBar(main_window,self.tabbedToolsWidget, main_window)\n        main_window.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar)\n\n        # Add status bar to the main window\n        self.statusbar = QtWidgets.QStatusBar(main_window)\n        self.statusbar.setObjectName('statusbar')\n        main_window.setStatusBar(self.statusbar)\n\n        # Add central Widget to the main window\n        main_window.setCentralWidget(self.centralwidget)\n\n"
  },
  {
    "path": "src/gui/sharedcomnponets/commandLineInterface.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom PyQt5 import (QtGui, QtWidgets)\n\nfrom src.gui.sharedcomnponets.sharedcomponets import GUIToolKit\nfrom src.simpleFOCConnector import SimpleFOCDevice\n\n\nclass CommandLineWidget(QtWidgets.QGroupBox):\n\n    def __init__(self, parent=None):\n        super().__init__(parent)\n\n        self.device = SimpleFOCDevice.getInstance()\n\n        self.setObjectName('groupBox')\n        self.setTitle('Command Line interface')\n\n        self.cmlVerticalLayout = QtWidgets.QVBoxLayout(self)\n        self.cmlVerticalLayout.setObjectName('cmlVerticalLayout')\n\n        self.commandLineDisplay = QtWidgets.QTextEdit(self)\n        self.commandLineDisplay.setObjectName('commandLineDisplay')\n        self.cmlVerticalLayout.addWidget(self.commandLineDisplay)\n\n        self.commandLineDisplay.setReadOnly(True)\n        self.commandLineDisplay.setTextColor(QtGui.QColor(68, 117, 68, 255))\n\n        self.cmlWidget = QtWidgets.QWidget(self)\n        self.cmlWidget.setObjectName('cmlWidget')\n        self.cmlHorizontalLayout = QtWidgets.QHBoxLayout(self.cmlWidget)\n        self.cmlHorizontalLayout.setObjectName('cmlHorizontalLayout')\n\n        self.commandLineEdit = QtWidgets.QLineEdit(self.cmlWidget)\n        self.commandLineEdit.setObjectName('commandLineEdit')\n        self.cmlHorizontalLayout.addWidget(self.commandLineEdit)\n\n        self.commandLineEdit.returnPressed.connect(self.sendAction)\n\n        self.sendButton = QtWidgets.QPushButton(self.cmlWidget)\n        self.sendButton.setObjectName('sendButton')\n        self.sendButton.setText('Send')\n        self.sendButton.setIcon(GUIToolKit.getIconByName('send'))\n        self.sendButton.clicked.connect(self.sendAction)\n\n        self.cmlHorizontalLayout.addWidget(self.sendButton)\n\n        self.clearButton = QtWidgets.QPushButton(self.cmlWidget)\n        self.clearButton.setObjectName('clearButton')\n        self.cmlHorizontalLayout.addWidget(self.clearButton)\n        self.clearButton.setIcon(GUIToolKit.getIconByName('delete'))\n        self.clearButton.clicked.connect(self.clearAction)\n        self.clearButton.setText('Clear')\n        \n        self.listDevices = QtWidgets.QPushButton(self.cmlWidget)\n        self.listDevices.setObjectName('listDevices')\n        self.cmlHorizontalLayout.addWidget(self.listDevices)\n        self.listDevices.setIcon(GUIToolKit.getIconByName('list'))\n        self.listDevices.clicked.connect(self.sendListDevices)\n        self.listDevices.setText('List Devices')\n\n        self.cmlVerticalLayout.addWidget(self.cmlWidget)\n        self.device.addConnectionStateListener(self)\n        self.setEnabled(False)\n\n    def connectionStateChanged(self, deviceConnected):\n        if deviceConnected is True:\n            self.enabeUI()\n            self.publishCommandResponseData('Connected ...')\n        else:\n            self.disableUI()\n            self.publishCommandResponseData('Disconnected ...')\n\n    def enabeUI(self):\n\n        self.commandLineDisplay.setEnabled(True)\n        self.cmlWidget.setEnabled(True)\n        self.commandLineEdit.setEnabled(True)\n        self.sendButton.setEnabled(True)\n\n        self.setEnabled(True)\n\n    def disableUI(self):\n        # self.commandLineDisplay.setEnabled(False)\n        self.commandLineEdit.setEnabled(False)\n        self.sendButton.setEnabled(False)\n\n    def publishCommandResponseData(self, data):\n        self.commandLineDisplay.append(data)\n        self.commandLineDisplay.moveCursor(QtGui.QTextCursor.End)\n\n    def clearAction(self):\n        self.commandLineDisplay.setPlainText('')\n\n    def sendAction(self):\n        self.device.sendCommand(self.commandLineEdit.text())\n        self.commandLineEdit.setText('')\n        \n    def sendListDevices(self):\n        self.device.sendCommand('?')\n"
  },
  {
    "path": "src/gui/sharedcomnponets/sharedcomponets.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nimport os\nfrom PyQt5 import (QtGui, QtWidgets,QtCore)\nfrom serial.tools import list_ports\n\n\nclass GUIToolKit(object):\n    ''' This class is used to provide icons for the rest of the application\n        hiding the location of the resources\n    '''\n    RED_COLOR = (255, 92, 92)\n    GREEN_COLOR = (57, 217, 138)\n    BLUE_COLOR = (91, 141, 236)\n    ORANGE_COLOR = (253, 172, 66)\n    YELLOW_COLOR = (255,255,51)\n    PURPLE_COLOR = (75,0,130)\n    MAROON_COLOR = (222,184,135)\n\n    @staticmethod\n    def getIconByName(icoName):\n\n        file_index = {\n            'add': 'add.png',\n            'add_motor': 'add_motor.png',\n            'tree': 'tree.png',\n            'gen': 'gen.png',\n            'home': 'home.png',\n            'form': 'form.png',\n            'edit': 'edit.png',\n            'delete': 'delete.png',\n            'statistics': 'statistics.png',\n            'reddot': 'reddot.png',\n            'orangedot': 'orangedot.png',\n            'greendot': 'greendot.png',\n            'bluedot': 'bluedot.png',\n            'purpledot': 'purpledot.png',\n            'yellowdot': 'yellowdot.png',\n            'maroondot': 'maroondot.png',\n            'send': 'send.png',\n            'zoomall': 'zoomall.png',\n            'connect': 'connect.png',\n            'continue': 'continue.png',\n            'alert': 'alert.png',\n            'gear': 'gear.png',\n            'generalsettings': 'generalsettings.png',\n            'open': 'open.png',\n            'loop': 'loop.png',\n            'save': 'save.png',\n            'stop': 'stop.png',\n            'restart': 'continue.png',\n            'res': 'res.png',\n            'sensor': 'sensor.png',\n            'start': 'start.png',\n            'motor': 'motor.png',\n            'pause': 'pause.png',\n            'pull': 'pull.png',\n            'push': 'push.png',\n            'list': 'list.png',\n            'disconnect': 'disconnect.png',\n            'configure': 'configure.png',\n            'pidconfig': 'pidconfig.png',\n            'consoletool': 'consoletool.png',\n            'fordward': 'fordward.png',\n            'fastbackward': 'fastbackward.png',\n            'backward': 'backward.png',\n            'stopjogging': 'stopjogging.png',\n            'fastfordward': 'fastfordward.png',\n            'customcommands':'customcommands.png'\n        }\n        currentDir = os.path.dirname(__file__)\n        icon_path = os.path.join(currentDir, '../resources', file_index[icoName])\n        icon = QtGui.QIcon()\n        icon.addPixmap(QtGui.QPixmap(icon_path), QtGui.QIcon.Normal,\n                      QtGui.QIcon.Off)\n        return icon\n\n\nclass ConfigQLineEdit(QtWidgets.QLineEdit):\n    return_key = 16777220\n    updateValue = QtCore.pyqtSignal()\n    def __init__(self, parent=None):\n        '''Constructor for ToolsWidget'''\n        super().__init__(parent)\n\n    def keyPressEvent(self, event):\n        if event.key() == self.return_key:\n            self.updateValue.emit()\n        else:\n            super().keyPressEvent(event)\n\nclass WorkAreaTabWidget(QtWidgets.QTabWidget):\n    def __init__(self, parent=None):\n        '''Constructor for ToolsWidget'''\n        super().__init__(parent)\n\n    def getTabIcon(self):\n        raise NotImplemented\n\n    def getTabName(self):\n        raise NotImplemented\n\nclass SerialPortComboBox(QtWidgets.QComboBox):\n    def __init__(self, parent=None, snifer=None):\n        super().__init__(parent)\n        self.addItems(self.getAvailableSerialPortNames())\n\n    def getAvailableSerialPortNames(self):\n        portNames = []\n        for port in list_ports.comports():\n            if port[2] != 'n/a':\n                portNames.append(port[0])\n\n        return portNames\n\n    def showPopup(self):\n        selectedItem = self.currentText()\n        super().clear()\n        availableSerialPortNames = self.getAvailableSerialPortNames()\n        self.addItems(availableSerialPortNames)\n        if selectedItem in availableSerialPortNames:\n            self.setCurrentText(selectedItem)\n        super().showPopup()\n"
  },
  {
    "path": "src/gui/toolbar.py",
    "content": "# !/usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom PyQt5 import QtWidgets\nfrom src.gui.sharedcomnponets.sharedcomponets import GUIToolKit\n\n\nclass SimpleFOCConfigToolBar(QtWidgets.QToolBar):\n\n    def __init__(self,main_window, devicesTabedWidget,  parent=None):\n        super().__init__(parent)\n        \n        self.addDeviceAction = QtWidgets.QToolButton(main_window)\n        self.addDeviceAction.setIcon(GUIToolKit.getIconByName('add_motor'))\n        self.addDeviceAction.setObjectName('addDeviceAction')\n        self.addDeviceAction.setPopupMode(QtWidgets.QToolButton.InstantPopup)\n\n        self.addDeviceMenu = QtWidgets.QMenu(self.addDeviceAction)\n        self.addDeviceTreeView  = QtWidgets.QAction(\"Tree View\",self.addDeviceMenu)\n        self.addDeviceTreeView.setIcon(GUIToolKit.getIconByName('tree'))\n        self.addDeviceTreeView.triggered.connect(devicesTabedWidget.addDeviceTree)\n        self.addDeviceFormView  = QtWidgets.QAction(\"Form View\",self.addDeviceMenu)\n        self.addDeviceFormView.setIcon(GUIToolKit.getIconByName('form'))\n        self.addDeviceFormView.triggered.connect(devicesTabedWidget.addDeviceForm)\n        \n        self.addDeviceMenu.addAction(self.addDeviceTreeView)\n        self.addDeviceMenu.addAction(self.addDeviceFormView)\n        self.addDeviceAction.setMenu(self.addDeviceMenu)\n        self.addWidget(self.addDeviceAction)\n\n        self.openDeviceAction = QtWidgets.QAction(main_window)\n        self.openDeviceAction.setIcon(GUIToolKit.getIconByName('open'))\n        self.openDeviceAction.setObjectName('openDeviceAction')\n        self.openDeviceAction.triggered.connect(devicesTabedWidget.openDevice)\n\n        self.addAction(self.openDeviceAction)\n\n        self.saveDeviceAction = QtWidgets.QAction(main_window)\n        self.saveDeviceAction.setIcon(GUIToolKit.getIconByName('save'))\n        self.saveDeviceAction.setObjectName('saveDeviceAction')\n        self.saveDeviceAction.triggered.connect(devicesTabedWidget.saveDevice)\n\n        self.addAction(self.saveDeviceAction)\n\n        self.generateCodeAction = QtWidgets.QAction(main_window)\n        self.generateCodeAction.setIcon(GUIToolKit.getIconByName('gen'))\n        self.generateCodeAction.setObjectName('genertecode')\n        self.generateCodeAction.triggered.connect(devicesTabedWidget.generateCode)\n\n        self.addAction(self.generateCodeAction)\n        self.addSeparator()\n\n        self.openConsoleToolAction = QtWidgets.QAction(main_window)\n        self.openConsoleToolAction.setIcon(GUIToolKit.getIconByName('consoletool'))\n        self.openConsoleToolAction.setToolTip('Open Serial Cosole tool')\n        self.openConsoleToolAction.setObjectName('openconsoletool')\n        self.openConsoleToolAction.triggered.connect(devicesTabedWidget.openConsoleTool)\n\n        self.addAction(self.openConsoleToolAction)\n\n        self.addSeparator()\n"
  },
  {
    "path": "src/gui/workAreaTabbedWidget.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nimport json\nfrom PyQt5 import QtWidgets\nfrom src.gui.commandlinetool.commandlinetool import CommandLineConsoleTool\nfrom src.gui.configtool.deviceConfigurationTool import DeviceConfigurationTool\nfrom src.gui.configtool.generatedCodeDisplay import GeneratedCodeDisplay\nfrom src.gui.configtool.treeViewConfigTool import TreeViewConfigTool\nfrom src.simpleFOCConnector import SimpleFOCDevice\n\n\nclass WorkAreaTabbedWidget(QtWidgets.QTabWidget):\n\n    def __init__(self, parent=None):\n        super().__init__(parent)\n        self.setTabsClosable(True)\n        self.setMovable(True)\n        self.setObjectName('devicesTabWidget')\n\n        self.device = SimpleFOCDevice.getInstance()\n\n        self.cmdLineTool = None\n        self.configDeviceTool = None\n        self.generatedCodeTab = None\n        self.activeToolsList = []\n\n        self.tabCloseRequested.connect(self.removeTabHandler)\n\n        self.setStyleSheet(\n            'QTabBar::close - button { image: url(close.png) subcontrol - position: left; }')\n        self.setStyleSheet('QTabBar::tab { height: 30px; width: 150px;}')\n\n    def removeTabHandler(self, index):\n        if type(self.currentWidget()) == CommandLineConsoleTool:\n            self.cmdLineTool = None\n        if type(self.currentWidget()) == DeviceConfigurationTool or type(\n                self.currentWidget()) == TreeViewConfigTool:\n            self.configDeviceTool = None\n        if type(self.currentWidget()) == GeneratedCodeDisplay:\n            self.generatedCodeTab = None\n        if self.configDeviceTool == None and self.cmdLineTool == None:\n            if self.device.isConnected:\n                self.device.disConnect()\n\n        self.activeToolsList.pop(index)\n        self.removeTab(index)\n\n    def addDeviceForm(self):\n        if self.configDeviceTool is None:\n            self.configDeviceTool = DeviceConfigurationTool()\n            self.activeToolsList.append(self.configDeviceTool)\n            self.addTab(self.configDeviceTool,\n                        self.configDeviceTool.getTabIcon(), 'Device')\n            self.setCurrentIndex(self.currentIndex() + 1)\n            \n    def addDeviceTree(self):\n        if self.configDeviceTool is None:\n            self.configDeviceTool = TreeViewConfigTool()\n            self.activeToolsList.append(self.configDeviceTool)\n            self.addTab(self.configDeviceTool,\n                        self.configDeviceTool.getTabIcon(), 'Device')\n            self.setCurrentIndex(self.currentIndex() + 1)\n\n    def openDevice(self):\n        if self.configDeviceTool is None:\n            dlg = QtWidgets.QFileDialog()\n            dlg.setFileMode(QtWidgets.QFileDialog.AnyFile)\n            filenames = None\n            if dlg.exec_():\n                filenames = dlg.selectedFiles()\n                try:\n                    with open(filenames[0]) as json_file:\n                        configurationInfo = json.load(json_file)\n                        sfd = SimpleFOCDevice.getInstance()\n                        sfd.configureDevice(configurationInfo)\n                        self.configDeviceTool = TreeViewConfigTool()\n                        sfd.openedFile = filenames\n                        self.activeToolsList.append(self.configDeviceTool)\n                        tabName = self.configDeviceTool.getTabName()\n                        if tabName == '':\n                            tabName = 'Device'\n                        self.addTab(self.configDeviceTool,\n                                    self.configDeviceTool.getTabIcon(), tabName)\n                        self.setCurrentIndex(self.currentIndex() + 1)\n\n                except Exception as exception:\n                    msgBox = QtWidgets.QMessageBox()\n                    msgBox.setIcon(QtWidgets.QMessageBox.Warning)\n                    msgBox.setText('Error while opening selected file')\n                    msgBox.setWindowTitle('SimpleFOC configDeviceTool')\n                    msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok)\n                    msgBox.exec()\n\n    def saveDevice(self):\n        if len(self.activeToolsList) > 0:\n            currentconfigDeviceTool = self.activeToolsList[self.currentIndex()]\n            if currentconfigDeviceTool.device.openedFile is None:\n                options = QtWidgets.QFileDialog.Options()\n                options |= QtWidgets.QFileDialog.DontUseNativeDialog\n                fileName, _ = QtWidgets.QFileDialog.getSaveFileName(self,\n                                                                    'Save device configuration',\n                                                                    '',\n                                                                    'JSON configuration file (*.json)',\n                                                                    options=options)\n                if fileName:\n                    self.saveToFile(currentconfigDeviceTool.device, fileName)\n            else:\n                self.saveToFile(currentconfigDeviceTool.device,\n                                currentconfigDeviceTool.device.openedFile)\n                                \n    def generateCode(self):\n        if len(self.activeToolsList) > 0:\n            currentconfigDeviceTool = self.activeToolsList[self.currentIndex()]\n            self.generatedCodeTab = GeneratedCodeDisplay()\n            self.activeToolsList.append(self.generatedCodeTab)\n            self.addTab(self.generatedCodeTab,\n                        self.generatedCodeTab.getTabIcon(), self.generatedCodeTab.getTabName())\n            self.setCurrentIndex(self.currentIndex() + 1)\n\n\n    def saveToFile(self, deviceToSave, file):\n        if type(file) is list:\n            with open(file[0], 'w', encoding='utf-8') as f:\n                f.write(json.dumps(deviceToSave.toJSON(), indent=4, sort_keys=True))\n        else:\n            with open(file, 'w', encoding='utf-8') as f:\n                f.write(json.dumps(deviceToSave.toJSON(), indent=4, sort_keys=True))\n\n    def openConsoleTool(self):\n        if self.cmdLineTool is None:\n            self.cmdLineTool = CommandLineConsoleTool()\n            self.activeToolsList.append(self.cmdLineTool)\n            self.addTab(self.cmdLineTool,\n                        self.cmdLineTool.getTabIcon(), 'Cmd Line')\n            self.setCurrentIndex(self.currentIndex() + 1)\n"
  },
  {
    "path": "src/simpleFOCConnector.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nimport logging\nimport threading\nimport time\n\nimport serial\nfrom PyQt5 import QtCore, QtWidgets\nfrom serial import SerialException\nfrom collections import defaultdict\n\nclass PIDController:\n    P = 0\n    D = 0\n    I = 0\n    outputRamp = 0\n    outputLimit = 0\n    cmd =''\n\n    def __init__(self, cmd):\n        self.cmd = cmd\n    \n    def load(self, jsonValues):\n        self.P = jsonValues['P']\n        self.I = jsonValues['I']\n        self.D = jsonValues['D']\n        self.outputRamp = jsonValues['outputRamp']\n        self.outputLimit = jsonValues['outputLimit']\n\n    def serialize(self):\n        return {\n            'P': self.P,\n            'I': self.I,\n            'D': self.D,\n            'outputRamp':self.outputRamp,\n            'outputLimit':self.outputLimit\n        }\n\n\nclass LowPassFilter:\n    Tf = 0\n    cmd =''\n    cmdTf = 'F'\n\n    def __init__(self, cmd):\n        self.cmd = cmd\n\n\nclass Command:\n    cmdName = ''\n    cmd = ''\n\n    def __init__(self,cmdname='Command', cmd=''):\n        self.cmdName = cmdname\n        self.cmd = cmd\n\n    def load(self, jsonValues):\n        self.cmdName = jsonValues['commandName']\n        self.cmd = jsonValues['commandValue']\n\n    def serialize(self):\n        return {\n            'commandName': self.cmdName,\n            'commandValue': self.cmd\n        }\n\n\nclass CustomCommands:\n    customCommandsList = []\n\n    def __init__(self,commandsLis=[]):\n        for command in  commandsLis:\n            self.customCommandsList.append(command)\n    def load(self, jsonValues):\n        for commandInJson in jsonValues:\n            command = Command()\n            command.load(commandInJson)\n            self.customCommandsList.append(command)\n\n    def serialize(self):\n        serializedCustomCommands = defaultdict(list)\n        for command in self.customCommandsList:\n            serializedCommand = command.serialize()\n            serializedCustomCommands['customCommands'].append(serializedCommand)\n        return serializedCustomCommands\n\nclass SimpleFOCDevice:\n    __instance = None\n\n    TORQUE_CONTROL  = 0\n    VELOCITY_CONTROL = 1\n    ANGLE_CONTROL = 2\n    VELOCITY_OPENLOOP_CONTROL = 3\n    ANGLE_OPENLOOP_CONTROL = 4\n\n    SINE_PWM  = 0\n    SPACE_VECTOR_PWM = 1\n    TRAPEZOIDAL_120 = 2\n    TRAPEZOIDAL_150 = 3\n\n    VOLTAGE_TORQUE = 0\n    DC_CURRENT_TORQUE  = 1\n    FOC_CURRENT_TORQUE = 2\n\n    VELOCITY_PID = 'V'\n    ANGLE_PID = 'A'\n    CURRENT_Q_PID = 'Q'\n    CURRENT_D_PID = 'D'\n\n    PULL_CONFIG_ON_CONNECT = 'Pull config'\n    PUSH_CONFG_ON_CONNECT = 'Push config'\n    ONLY_CONNECT = 'Only connect'\n\n    @staticmethod\n    def getInstance():\n        \"\"\" Static access method. \"\"\"\n        if SimpleFOCDevice.__instance == None:\n            SimpleFOCDevice()\n        return SimpleFOCDevice.__instance\n\n    def __init__(self):\n        \"\"\" Virtually private constructor. \"\"\"\n        if SimpleFOCDevice.__instance != None:\n            raise Exception(\"This class is a singleton!\")\n        else:\n            # serial connection variables\n            self.serialPort = None\n            self.responseThread = None\n            self.isConnected = False\n            self.openedFile = None\n\n            self.connectionStateListenerList = []\n\n            self.serialPortName = \"\"\n            self.serialRate = 115200\n            self.serialByteSize = serial.EIGHTBITS\n            self.serialParity = serial.PARITY_NONE\n            self.stopBits = serial.STOPBITS_ONE\n            self.commProvider = SerialPortReceiveHandler()\n            self.commProvider.commandDataReceived.connect(self.parseResponses)\n            self.commProvider.stateMonitorReceived.connect(self.parseStateResponses)\n            self.connectionID = \"\"\n\n            # command id of the device\n            self.devCommandID = ''\n\n            # motion control paramters\n            self.PIDVelocity = PIDController(self.VELOCITY_PID)\n            self.PIDAngle = PIDController(self.ANGLE_PID)\n            self.PIDCurrentQ = PIDController(self.CURRENT_Q_PID)\n            self.PIDCurrentD = PIDController(self.CURRENT_D_PID)\n            self.LPFVelocity = LowPassFilter(self.VELOCITY_PID)\n            self.LPFAngle = LowPassFilter(self.ANGLE_PID)\n            self.LPFCurrentQ = LowPassFilter(self.CURRENT_Q_PID)\n            self.LPFCurrentD = LowPassFilter(self.CURRENT_D_PID)\n            self.velocityLimit = 0\n            self.voltageLimit = 0\n            self.currentLimit = 0\n            self.controlType =  SimpleFOCDevice.ANGLE_CONTROL\n            self.torqueType =  SimpleFOCDevice.VOLTAGE_TORQUE\n            self.initialTarget = 0\n            self.motionDownsample = 0\n\n            # monitor variables\n            self.monitorDownsample = 0\n            self.monitorVariables = 0\n\n            # state variables\n            self.target = 0\n            self.stateUpdater = StateUpdateRunner(self)\n            self.targetNow = 0\n            self.angleNow = 0\n            self.velocityNow = 0\n            self.voltageQNow = 0\n            self.voltageDNow = 0\n            self.currentQNow = 0\n            self.currentDNow = 0\n\n            # general variables\n            self.phaseResistance = 0\n            self.deviceStatus = 0\n            self.modulationType = 0\n            self.modulationCentered = 1\n\n            # sensor variables\n            self.sensorElectricalZero = 0\n            self.sensorZeroOffset = 0\n\n            # list of custom commands\n            self.customCommands = CustomCommands()\n\n            # return the class instance\n            SimpleFOCDevice.__instance = self\n\n\n    def configureDevice(self, jsonValue):\n        # motion control parameters\n        self.PIDVelocity.load(jsonValue['PIDVelocity'])\n        self.PIDAngle.load(jsonValue['PIDAngle'])\n        self.PIDCurrentD.load(jsonValue['PIDCurrentD'])\n        self.PIDCurrentQ.load(jsonValue['PIDCurrentQ'])\n        \n        # low pass filters\n        self.LPFVelocity.Tf = jsonValue['LPFVelocity']\n        self.LPFAngle.Tf = jsonValue['LPFAngle']\n        self.LPFCurrentQ.Tf = jsonValue['LPFCurrentQ']\n        self.LPFCurrentD.Tf = jsonValue['LPFCurrentD']\n        # limit variables\n        self.velocityLimit = jsonValue['velocityLimit']\n        self.voltageLimit = jsonValue['voltageLimit']\n        self.currentLimit = jsonValue['currentLimit']\n        # motion control types\n        self.controlType = jsonValue['controlType']\n        self.torqueType = jsonValue['torqueType']\n        self.motionDownsample = jsonValue['motionDownsample']\n\n        # sensor zero offset and electrical zero offset\n        self.sensorElectricalZero = jsonValue['sensorElectricalZero']\n        self.sensorZeroOffset = jsonValue['sensorZeroOffset']\n\n        # motor phase resistance\n        self.phaseResistance = jsonValue['phaseResistance']\n\n        # initial target\n        self.initialTarget = jsonValue['initialTarget']\n    \n        # serial communication variables\n        self.connectionID = jsonValue['connectionID']\n        self.serialPortName = jsonValue['serialPortName']\n        self.serialRate = jsonValue['serialRate']\n        self.serialByteSize = jsonValue['serialByteSize']\n        self.serialParity = jsonValue['serialParity']\n        self.stopBits = jsonValue['stopBits']\n        try:\n            self.customCommands.customCommandsList = []\n            self.customCommands.load(jsonValue['customCommands'])\n        except KeyError:\n            pass\n        try:\n            self.devCommandID = jsonValue['devCommandID']\n        except KeyError:\n            pass\n\n    def configureConnection(self, configDict):\n        self.connectionID = configDict['connectionID']\n        self.serialPortName = configDict['serialPortName']\n        self.serialRate = configDict['serialRate']\n        self.serialByteSize = configDict['serialByteSize']\n        self.serialParity = configDict['serialParity']\n        self.stopBits = configDict['stopBits']\n\n    def toJSON(self):\n        valuesToSave = {\n            'PIDVelocity': self.PIDVelocity.serialize(),\n            'PIDAngle': self.PIDAngle.serialize(),\n            'PIDCurrentD': self.PIDCurrentD.serialize(),\n            'PIDCurrentQ': self.PIDCurrentQ.serialize(),\n            'LPFVelocity':self.LPFVelocity.Tf,\n            'LPFAngle':self.LPFAngle.Tf,\n            'LPFCurrentD':self.LPFCurrentD.Tf,\n            'LPFCurrentQ':self.LPFCurrentQ.Tf,\n            'velocityLimit': self.velocityLimit,\n            'voltageLimit': self.voltageLimit,\n            'currentLimit': self.currentLimit,\n            'controlType': self.controlType,\n            'motionDownsample':self.motionDownsample,\n            'torqueType': self.torqueType,\n            'phaseResistance': self.phaseResistance,\n            'sensorZeroOffset': self.sensorZeroOffset,\n            'sensorElectricalZero': self.sensorElectricalZero,\n            'initialTarget': self.initialTarget,\n            'connectionID': self.connectionID,\n            'serialPortName': self.serialPortName,\n            'serialRate': self.serialRate,\n            'serialByteSize': self.serialByteSize,\n            'serialParity': self.serialParity,\n            'stopBits': self.stopBits,\n            'devCommandID': self.devCommandID,\n\n        }\n        valuesToSave.update(self.customCommands.serialize())\n        return valuesToSave\n\n        \n    def toArduinoCode(self, generateParams = []):\n\n        # code = \"#include <SimpleFOC.h>\\n\\n\"\n        # code += \"void setup(){\\n\\n\"\n        # code += \"....\\n\\n\"\n        code = \"\\n\"\n        if generateParams[0] or generateParams==[]:\n            code += \"// control loop type and torque mode \\n\"\n            code += \"motor.torque_controller = TorqueControlType::\"\n            if self.torqueType == self.VOLTAGE_TORQUE:\n                code += \"voltage\"\n            elif self.torqueType == self.DC_CURRENT_TORQUE:\n                code += \"dc_current\"\n            elif self.torqueType == self.FOC_CURRENT_TORQUE:\n                code += \"foc_current\"\n            code += \";\\n\"\n            code += \"motor.controller = MotionControlType::\"\n            if self.controlType == self.TORQUE_CONTROL:\n                code += \"torque\"\n            elif self.controlType == self.VELOCITY_CONTROL:\n                code += \"velocity\"\n            elif self.controlType == self.ANGLE_CONTROL:\n                code += \"angle\"\n            elif self.controlType == self.VELOCITY_CONTROL:\n                code += \"velocity_openloop\"\n            elif self.controlType == self.ANGLE_CONTROL:\n                code += \"angle_openloop\"\n            code += \";\\n\"\n            code += \"motor.motion_downsample = \" + str(self.motionDownsample) +\";\\n\" \n            code += \"\\n\"\n\n        if generateParams[1] or generateParams==[]:\n            code += \"// velocity loop PID\\n\"  \n            code += \"motor.PID_velocity.P = \" + str(self.PIDVelocity.P) +\";\\n\"  \n            code += \"motor.PID_velocity.I = \" + str(self.PIDVelocity.I) +\";\\n\"  \n            code += \"motor.PID_velocity.D = \" + str(self.PIDVelocity.D) +\";\\n\"  \n            code += \"motor.PID_velocity.output_ramp = \" + str(self.PIDVelocity.outputRamp) +\";\\n\"  \n            code += \"motor.PID_velocity.limit = \" + str(self.PIDVelocity.outputLimit) +\";\\n\"  \n            code += \"// Low pass filtering time constant \\n\"  \n            code += \"motor.LPF_velocity.Tf = \" + str(self.LPFVelocity.Tf) +\";\\n\"  \n        if generateParams[2] or generateParams==[]:\n            code += \"// angle loop PID\\n\"\n            code += \"motor.P_angle.P = \" + str(self.PIDAngle.P) +\";\\n\"  \n            code += \"motor.P_angle.I = \" + str(self.PIDAngle.I) +\";\\n\"   \n            code += \"motor.P_angle.D = \" + str(self.PIDAngle.D) +\";\\n\"    \n            code += \"motor.P_angle.output_ramp = \" + str(self.PIDAngle.outputRamp) +\";\\n\"   \n            code += \"motor.P_angle.limit = \" + str(self.PIDAngle.outputLimit) +\";\\n\"  \n            code += \"// Low pass filtering time constant \\n\" \n            code += \"motor.LPF_angle.Tf = \" + str(self.LPFAngle.Tf) +\";\\n\"  \n        if generateParams[3] or generateParams==[]: \n            code += \"// current q loop PID \\n\"\n            code += \"motor.PID_current_q.P = \" + str(self.PIDCurrentQ.P) +\";\\n\"  \n            code += \"motor.PID_current_q.I = \" + str(self.PIDCurrentQ.I) +\";\\n\"   \n            code += \"motor.PID_current_q.D = \" + str(self.PIDCurrentQ.D) +\";\\n\"   \n            code += \"motor.PID_current_q.output_ramp = \" + str(self.PIDCurrentQ.outputRamp) +\";\\n\"  \n            code += \"motor.PID_current_q.limit = \" + str(self.PIDCurrentQ.outputLimit) +\";\\n\"  \n            code += \"// Low pass filtering time constant \\n\" \n            code += \"motor.LPF_current_q.Tf = \" + str(self.LPFCurrentQ.Tf) +\";\\n\"  \n        if generateParams[4] or generateParams==[]:\n            code += \"// current d loop PID\\n\"\n            code += \"motor.PID_current_d.P = \" + str(self.PIDCurrentD.P) +\";\\n\"   \n            code += \"motor.PID_current_d.I = \" + str(self.PIDCurrentD.I) +\";\\n\"  \n            code += \"motor.PID_current_d.D = \" + str(self.PIDCurrentD.D) +\";\\n\"  \n            code += \"motor.PID_current_d.output_ramp = \" + str(self.PIDCurrentD.outputRamp) +\";\\n\"   \n            code += \"motor.PID_current_d.limit = \" + str(self.PIDCurrentD.outputLimit) +\";\\n\"  \n            code += \"// Low pass filtering time constant \\n\" \n            code += \"motor.LPF_current_d.Tf = \" + str(self.LPFCurrentD.Tf) +\";\\n\" \n \n        if generateParams[5] or generateParams==[]:\n            code += \"// Limits \\n\"\n            code += \"motor.velocity_limit = \" + str(self.velocityLimit) +\";\\n\" \n            code += \"motor.voltage_limit = \" + str(self.voltageLimit) +\";\\n\" \n            code += \"motor.current_limit = \" + str(self.currentLimit) +\";\\n\" \n\n        if generateParams[6] or generateParams==[]:\n            code += \"// sensor zero offset - home position \\n\"\n            code += \"motor.sensor_offset = \" + str(self.sensorZeroOffset) +\";\\n\" \n\n        if generateParams[7] or generateParams==[]:\n            code += \"// sensor zero electrical angle \\n\"\n            code += \"// this parameter enables skipping a part of initFOC \\n\"\n            code += \"motor.sensor_electrical_offset = \" + str(self.sensorElectricalZero) +\";\\n\" \n\n        if generateParams[8] or generateParams==[]:\n            code += \"// general settings \\n\"\n            code += \"// motor phase resistance \\n\"\n            code += \"motor.phase_resistance = \" + str(self.sensorElectricalZero) +\";\\n\" \n            \n        if generateParams[9] or generateParams==[]:\n            code += \"// pwm modulation settings \\n\"\n            code += \"motor.foc_modulation = FOCModulationType::\"\n            if self.modulationType == self.SINE_PWM:\n                code += \"SinePWM\"\n            elif self.modulationType == self.SPACE_VECTOR_PWM:\n                code += \"SpaceVectorPWM\"\n            elif self.modulationType == self.TRAPEZOIDAL_120:\n                code += \"Trapezoid_120\"\n            elif self.modulationType == self.TRAPEZOIDAL_150:\n                code += \"Trapezoid_150\"\n            code += \";\\n\"\n            code += \"motor.modulation_centered = \" + str(self.modulationCentered) +\";\\n\" \n\n        # code += \"\\n\\nmotor.init();\\nmotor.initFOC();\\n\\n...\\n\\n }\"\n        # code += \"\\n\\nvoid loop() {\\n\\n....\\n\\n}\"\n        \n        return code\n\n    def __initCommunications(self):\n        self.serialPort = serial.Serial(self.serialPortName,\n                                        self.serialRate,\n                                        self.serialByteSize,\n                                        self.serialParity,\n                                        self.stopBits)\n\n        self.commProvider.serialComm = self.serialPort\n        self.commProvider.start()\n\n    def __closeCommunication(self):\n        self.serialPort.close()\n\n    def connect(self, connectionMode):\n        try:\n            self.__initCommunications()\n        except SerialException as serEx:\n            logging.warning('Is not possible to open serial port')\n            logging.warning('Port =' + self.serialPortName)\n            logging.warning('Rate =' + str(self.serialRate))\n            logging.warning('parity =' + str(self.serialParity))\n            logging.warning('Byte size =' + str(self.serialByteSize))\n            logging.warning('Stop bits=' + str(self.stopBits))\n\n            msgBox = QtWidgets.QMessageBox()\n            msgBox.setIcon(QtWidgets.QMessageBox.Warning)\n            msgBox.setText('Error while trying to open serial port')\n            msgBox.setWindowTitle('SimpleFOC ConfigTool')\n            msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok)\n            msgBox.exec()\n            return False\n        else:\n            self.isConnected = True\n            for listener in self.connectionStateListenerList:\n                listener.connectionStateChanged(True)\n            if connectionMode == SimpleFOCDevice.PULL_CONFIG_ON_CONNECT:\n                self.pullConfiguration()\n                if self.stateUpdater.stopped():\n                    self.stateUpdater = StateUpdateRunner(self)\n                self.stateUpdater.start()\n            elif connectionMode == SimpleFOCDevice.PUSH_CONFG_ON_CONNECT:\n                self.pushConfiguration()\n                if self.stateUpdater.stopped():\n                    self.stateUpdater = StateUpdateRunner(self)\n                self.stateUpdater.start()\n                pass\n            return True\n\n    def disConnect(self):\n        self.isConnected = False\n        self.__closeCommunication()\n        self.stateUpdater.stop()\n        for listener in self.connectionStateListenerList:\n            listener.connectionStateChanged(False)\n\n    def addConnectionStateListener(self, listener):\n        self.connectionStateListenerList.append(listener)\n\n    def sendCommand(self, command):\n        if self.isConnected:\n            self.serialPort.write((str(command) + '\\n').encode('utf-8'))\n\n    def setCommand(self, command, value):\n        if self.isConnected:\n           self.sendCommand(str(self.devCommandID) + str(command) + str(value))\n\n    def getCommand(self, command):\n        if self.isConnected:\n           self.sendCommand(str(self.devCommandID) + str(command) )\n\n    def sendControlType(self, loop_control_type):\n        if self.isConnected:\n            if loop_control_type  != '':\n                self.controlType = loop_control_type    \n            self.setCommand('C', str(loop_control_type))\n            \n    def sendTorqueType(self, torque_type):\n        if self.isConnected:\n            if torque_type  != '':\n                self.torqueType = torque_type    \n            self.setCommand('T', str(torque_type))\n            \n    def sendMotionDownsample(self, value):\n        if self.isConnected:\n            if value  != '':\n                self.motionDownsample = value    \n            self.setCommand('CD', str(value))\n\n    def sendProportionalGain(self, pid, value ):\n        if self.isConnected:\n            if value  != '':\n                pid.P = value\n            self.setCommand(str(pid.cmd)+'P',  str(value))\n\n    def sendIntegralGain(self, pid, value):\n        if self.isConnected:\n            if value  != '':\n                pid.I = value\n            self.setCommand(str(pid.cmd)+'I', str(value))\n\n    def sendDerivativeGain(self, pid,  value):\n        if self.isConnected:\n            if value  != '':\n                pid.D = value\n            self.setCommand(str(pid.cmd)+'D', str(value))\n\n    def sendOutputRamp(self, pid, value):\n        if self.isConnected:\n            if value  != '':\n                pid.outputRamp = value\n            self.setCommand(str(pid.cmd)+'R', str(value))\n\n    def sendOutputLimit(self, pid, value):\n        if self.isConnected:\n            if value  != '':\n                pid.outputLimit = value\n            self.setCommand(str(pid.cmd)+'L', str(value))\n\n    def sendLowPassFilter(self, lpf, value):\n        if self.isConnected:\n            if value  != '':\n                lpf.Tf = value\n            self.setCommand(str(lpf.cmd)+'F', str(value))\n\n    def sendVelocityLimit(self, value):\n        if self.isConnected:\n            if value  != '':\n                self.velocityLimit = value\n            self.setCommand('LV', str(value))\n\n    def sendVoltageLimit(self, value):\n        if self.isConnected:\n            if value  != '':\n                self.voltageLimit = value\n            self.setCommand('LU', str(value))\n\n    def sendCurrentLimit(self, value):\n        if self.isConnected:\n            if value  != '':\n                self.currentLimit = value\n            self.setCommand('LC', str(value))\n\n    def sendPhaseResistance(self, value):\n        if self.isConnected:\n            if value  != '':\n                self.phaseResistance = value\n            self.setCommand('R', str(value))\n\n    def sendTargetValue(self, targetvalue):\n        if self.isConnected:\n            if targetvalue  != '':\n                self.target = targetvalue\n            self.setCommand('',self.target)\n\n    def sendSensorZeroOffset(self, targetvalue):\n        if self.isConnected:\n            if targetvalue  != '':\n                self.sensorZeroOffset = targetvalue\n            self.setCommand('SM', str(targetvalue))\n\n    def sendSensorZeroElectrical(self, targetvalue):\n        if self.isConnected:\n            if targetvalue  != '':\n                self.sensorElectricalZero = targetvalue\n            self.setCommand('SE', str(targetvalue))\n\n    def sendDeviceStatus(self, targetvalue):\n        if self.isConnected:\n            if targetvalue != '':\n                self.deviceStatus = targetvalue\n            self.setCommand('E', str(targetvalue))\n\n            \n    def sendModulationCentered(self, targetvalue):\n        if self.isConnected:\n            if targetvalue != '':\n                self.modulationCentered = targetvalue\n            self.setCommand('WC', str(targetvalue))\n            \n    def sendModulationType(self, targetvalue):\n        if self.isConnected:\n            if targetvalue != '':\n                self.modulationType = targetvalue\n            self.setCommand('WT', str(targetvalue))\n            \n    def sendDeviceStatus(self, targetvalue):\n        if self.isConnected:\n            if targetvalue != '':\n                self.deviceStatus = targetvalue\n            self.setCommand('E', str(targetvalue))\n\n    def sendMonitorDownsample(self, targetvalue):\n        if self.isConnected:\n            if targetvalue != '':\n                self.monitorDownsample = targetvalue\n            self.setCommand('MD', str(targetvalue))\n\n    def sendMonitorClearVariables(self):\n        if self.isConnected:\n            self.monitorVariables = 0\n            self.getCommand('MC')\n\n    def sendMonitorVariables(self, vararray):\n        if self.isConnected:\n            if vararray != '':\n                val = 0\n                m  = 10**6\n                for var in vararray:\n                    val = val+ int(var)*m\n                    m = m/10\n                self.monitorVariables = vararray\n                self.setCommand('MS', \"{:07d}\".format(int(val)))\n            else:\n                self.getCommand('MS')\n\n\n    def updateStates(self):\n        if self.isConnected:\n            self.getCommand('MG0')\n            time.sleep(100 / 1000)\n            self.getCommand('MG1')\n            time.sleep(100 / 1000)\n            self.getCommand('MG2')\n            time.sleep(100 / 1000)\n            self.getCommand('MG3')\n            time.sleep(100 / 1000)\n            self.getCommand('MG4')\n            time.sleep(100 / 1000)\n            self.getCommand('MG5')\n            time.sleep(100 / 1000)\n            self.getCommand('MG6')\n            time.sleep(100 / 1000)\n\n\n    def pushConfiguration(self):\n        print(\"push\")\n        # self.sendControlType(self.controlType)\n        # self.sendProportionalGain(self.PIDVelocity, self.self)\n        # self.sendIntegralGain(self.PIDVelocity, self.integralGainPID)\n        # self.sendDerivativeGain(self.PIDVelocity, self.derivativeGainPID)\n        # self.sendOutputRamp(self.PIDVelocity, self.voltageRampPID)\n        # self.sendLowPassFilter(self.LPFVelocity,self.lowPassFilter)\n        # self.sendPGain(self.anglePGain)\n        # self.sendVelocityLimit(self.velocityLimit)\n        # self.sendVoltageLimit(self.voltageLimit)\n        # self.sendTargetValue(self.initialTarget)\n\n    def pullPIDConf(self, pid, lpf):\n        self.sendProportionalGain(pid,'')\n        time.sleep(5 / 1000)\n        self.sendIntegralGain(pid,'')\n        time.sleep(5 / 1000)\n        self.sendDerivativeGain(pid,'')\n        time.sleep(5 / 1000)\n        self.sendOutputRamp(pid,'')\n        time.sleep(5 / 1000)\n        self.sendOutputLimit(pid,'')\n        time.sleep(5 / 1000)\n        self.sendLowPassFilter(lpf,'')\n\n    def pullConfiguration(self):\n        time.sleep(5 / 1000)\n        self.sendControlType('')\n        time.sleep(5 / 1000)\n        self.sendTorqueType('')\n        time.sleep(5 / 1000)\n        self.pullPIDConf( self.PIDVelocity, self.LPFVelocity)\n        time.sleep(5 / 1000)\n        self.pullPIDConf( self.PIDAngle, self.LPFAngle)\n        time.sleep(5 / 1000)\n        self.pullPIDConf( self.PIDCurrentD, self.LPFCurrentD)\n        time.sleep(5 / 1000)\n        self.pullPIDConf( self.PIDCurrentQ, self.LPFCurrentQ)\n        time.sleep(5 / 1000)\n        self.sendVelocityLimit('')\n        time.sleep(5 / 1000)\n        self.sendVoltageLimit('')\n        time.sleep(5 / 1000)\n        self.sendCurrentLimit('')\n        time.sleep(5 / 1000)\n        self.sendSensorZeroElectrical('')\n        time.sleep(5 / 1000)\n        self.sendSensorZeroOffset('')\n        time.sleep(5 / 1000)\n        self.sendMotionDownsample('')\n        time.sleep(5 / 1000)\n        self.sendPhaseResistance('')\n        time.sleep(5 / 1000)\n        self.sendModulationCentered('')\n        time.sleep(5 / 1000)\n        self.sendModulationCentered('')\n        time.sleep(5 / 1000)\n        self.sendDeviceStatus('')\n\n    def parsePIDFResponse(self, pid, lpf, comandResponse):\n        if 'P' in comandResponse:\n            pid.P = float(comandResponse.replace('P: ', ''))\n        if 'I' in comandResponse:\n            pid.I = float(comandResponse.replace('I: ', ''))\n        if 'D' in comandResponse:\n            pid.D = float(comandResponse.replace('D: ', ''))\n        if 'ramp' in comandResponse:\n            val = comandResponse.replace('ramp:', '')\n            if 'ovf' in val:\n                pid.outputRamp = 0\n            else:\n                pid.outputRamp = float(comandResponse.replace('ramp:', ''))\n        if 'limit' in comandResponse:\n            pid.outputLimit = float(comandResponse.replace('limit:', ''))\n        if 'Tf' in comandResponse:\n            lpf.Tf = float(comandResponse.replace('Tf: ', ''))\n\n    def parseLimitsResponse(self, comandResponse):\n        if 'vel:' in comandResponse:\n            self.velocityLimit = float(comandResponse.replace('vel:', ''))\n        elif 'volt:' in comandResponse:\n            self.voltageLimit = float(comandResponse.replace('volt:', ''))\n        elif 'curr:' in comandResponse:\n            self.currentLimit = float(comandResponse.replace('curr:', ''))\n\n    def parseMotionResponse(self, comandResponse):\n        if 'downsample' in comandResponse:\n            self.motionDownsample = float(comandResponse.replace('downsample:', ''))\n        elif 'torque' in comandResponse:\n            self.controlType = 0\n        elif 'angle open' in comandResponse:\n            self.controlType = 4\n        elif 'angle' in comandResponse:\n            self.controlType = 2\n        elif 'vel open' in comandResponse:\n            self.controlType = 3\n        elif 'vel' in comandResponse:\n            self.controlType = 1\n            \n    def parsePWMModResponse(self, comandResponse):\n        if 'center' in comandResponse:\n            self.modulationCentered = float(comandResponse.replace('center:', ''))\n        elif 'type' in comandResponse:\n            comandResponse = comandResponse.replace('type:', '')\n            if 'Sine' in comandResponse:\n                self.modulationType = self.SINE_PWM\n            elif 'SVPWM' in comandResponse:\n                self.modulationType = self.SPACE_VECTOR_PWM\n            elif 'Trap 120' in comandResponse:\n                self.modulationType = self.TRAPEZOIDAL_120\n            elif 'Trap 150' in comandResponse:\n                self.modulationType = self.TRAPEZOIDAL_150\n            \n    def parseTorqueResponse(self, comandResponse):\n        if 'volt' in comandResponse:\n            self.torqueType = 0\n        elif 'dc curr' in comandResponse:\n            self.torqueType = 1\n        elif 'foc curr' in comandResponse:\n            self.torqueType = 2\n\n    def parseSensorResponse(self, comandResponse):\n        if 'el. offset' in comandResponse:\n            self.sensorElectricalZero = float(comandResponse.replace('el. offset:', ''))\n        elif 'offset' in comandResponse:\n            self.sensorZeroOffset = float(comandResponse.replace('offset:', ''))\n\n    def parseMonitorResponse(self, comandResponse):\n        if 'all' in comandResponse:\n            varStr = comandResponse.replace('all:', '')\n            states = varStr.rstrip().split('\\t', 7)\n            self.targetNow = states[0]\n            self.voltageQNow = states[1]\n            self.voltageDNow = states[2]\n            self.currentQNow = states[3]\n            self.currentDNow = states[4]\n            self.velocityNow = states[5]\n            self.angleNow = states[6]\n        if 'target' in comandResponse:\n            self.targetNow = float(comandResponse.replace('target:', ''))\n        elif 'Vq' in comandResponse:\n            self.voltageQNow = float(comandResponse.replace('Vq:', ''))\n        elif 'Vd' in comandResponse:\n            self.voltageDNow = float(comandResponse.replace('Vd:', ''))\n        elif 'Cq' in comandResponse:\n            self.currentQNow = float(comandResponse.replace('Cq:', ''))\n        elif 'Cd' in comandResponse:\n            self.currentDNow = float(comandResponse.replace('Cd:', ''))\n        elif 'vel' in comandResponse:\n            self.velocityNow = float(comandResponse.replace('vel:', ''))\n        elif 'angle' in comandResponse:\n            self.angleNow = float(comandResponse.replace('angle:', ''))\n\n    def parseResponses(self, comandResponse):\n        if 'PID vel' in comandResponse:\n            comandResponse = comandResponse.replace('PID vel|', '')\n            self.parsePIDFResponse(self.PIDVelocity, self.LPFVelocity, comandResponse)\n        elif 'PID angle' in comandResponse:\n            comandResponse = comandResponse.replace('PID angle|', '')\n            self.parsePIDFResponse(self.PIDAngle, self.LPFAngle, comandResponse)\n        elif 'PID curr q' in comandResponse:\n            comandResponse = comandResponse.replace('PID curr q|', '')\n            self.parsePIDFResponse(self.PIDCurrentQ, self.LPFCurrentQ, comandResponse)\n        elif 'PID curr d' in comandResponse:\n            comandResponse = comandResponse.replace('PID curr d|', '')\n            self.parsePIDFResponse(self.PIDCurrentD, self.LPFCurrentD, comandResponse)\n        elif 'Limits' in comandResponse:\n            comandResponse = comandResponse.replace('Limits|', '')\n            self.parseLimitsResponse(comandResponse)\n        elif 'Motion' in comandResponse:\n            comandResponse = comandResponse.replace('Motion:', '')\n            self.parseMotionResponse(comandResponse)\n        elif 'Torque' in comandResponse:\n            comandResponse = comandResponse.replace('Torque:', '')\n            self.parseTorqueResponse(comandResponse)\n        elif 'Sensor' in comandResponse:\n            comandResponse = comandResponse.replace('Sensor |', '')\n            self.parseSensorResponse(comandResponse)\n        elif 'Monitor' in comandResponse:\n            comandResponse = comandResponse.replace('Monitor |', '')\n            self.parseMonitorResponse(comandResponse)\n        elif 'Status' in comandResponse:\n            self.deviceStatus = float(comandResponse.replace('Status:', ''))\n        elif 'R phase' in comandResponse:\n            self.phaseResistance = float(comandResponse.replace('R phase:', ''))\n        elif 'PWM Mod' in comandResponse:\n            comandResponse = comandResponse.replace('PWM Mod | ', '')\n            self.parsePWMModResponse(comandResponse)\n\n    def parseStateResponses(self, comandResponse):\n        if 'Monitor' in comandResponse:\n            comandResponse = comandResponse.replace('Monitor |', '')\n            self.parseMonitorResponse(comandResponse)\n\n\nclass SerialPortReceiveHandler(QtCore.QThread):\n    monitoringDataReceived = QtCore.pyqtSignal(list)\n    commandDataReceived = QtCore.pyqtSignal(str)\n    stateMonitorReceived = QtCore.pyqtSignal(str)\n    rawDataReceived = QtCore.pyqtSignal(str)\n\n    def __init__(self, serial_port=None, *args,**kwargs):\n        super(SerialPortReceiveHandler, self).__init__(*args, **kwargs)\n        self._stop_event = threading.Event()\n        self.serialComm = serial_port\n\n    def handle_received_data(self, data):\n        if not data:\n            return\n            \n        if self.isDataReceivedMonitoring(data):\n            try:\n                v = data.rstrip().split('\\t')\n                self.monitoringDataReceived.emit(v)\n            except ValueError as error:\n                logging.error(error, exc_info=True)\n                logging.error('data =' + str(data), exc_info=True)\n            except IndexError as error:\n                logging.error(error, exc_info=True)\n                logging.error('data =' + str(data), exc_info=True)\n        elif self.isDataReceivedStates(data):\n            self.stateMonitorReceived.emit(data.rstrip())\n        else:\n            self.commandDataReceived.emit(data.rstrip())\n        self.rawDataReceived.emit(data.rstrip())\n\n    def isDataReceivedMonitoring(self, data):\n        if data[0].isdigit() or data[0] == '-':\n            return True\n        else:\n            return False\n            \n    def isDataReceivedStates(self, data):\n        if 'Monitor' in data:\n            return True\n        else:\n            return False\n\n    def run(self):\n        try:\n            while not self.stopped():\n                if self.serialComm is not None:\n                    if self.serialComm.isOpen():\n                        reading = self.serialComm.readline()\n                        if reading:\n                            self.handle_received_data(reading.decode())\n        except SerialException as serialException:\n            logging.error(serialException, exc_info=True)\n        except TypeError as typeError:\n            logging.error(typeError, exc_info=True)\n        except AttributeError as ae:\n            logging.error(ae, exc_info=True)            \n\n    def stop(self):\n        self._stop_event.set()\n\n    def stopped(self):\n        return self._stop_event.is_set()\n\n\nclass StateUpdateRunner(QtCore.QThread):\n\n    def __init__(self, connector=None, *args,**kwargs):\n        super(StateUpdateRunner, self).__init__(*args, **kwargs)\n        self._stop_event = threading.Event()\n        self.deviceConnector = connector\n    def run(self):\n        try:\n            while not self.stopped():\n                if self.deviceConnector is not None:\n                    if self.deviceConnector.commProvider.serialComm.isOpen():\n                        self.deviceConnector.updateStates()\n                        time.sleep(1)\n        except SerialException as serialException:\n            logging.error(serialException, exc_info=True)\n\n    def stop(self):\n        self._stop_event.set()\n\n    def stopped(self):\n        return self._stop_event.is_set()\n"
  }
]