diff --git a/README.md b/README.md index 724b60a..2a63783 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,48 @@ install arduino-cli -https://arduino.github.io/arduino-cli/0.33/installation/ \ No newline at end of file +https://arduino.github.io/arduino-cli/0.33/installation/ + + +### prerequisites + + arduino-cli + + python + + pyinstaller + +### install + + pip install -r requirements.txt + +### run + + python hemocube.py + + +### build + + pyinstaller --noconfirm --noconsole -i "smi.ico" --windowed --clean hemocube.py + +### build error + +>fqdn error: replace the check with nano fqdn explictly. +In Sketch.py of everywhereml/arduino replace line 167 and 228 with: + + + self.fqbn = 'arduino:avr:nano:cpu=atmega328old'` + + +>arduino library not found: manually copy all required libary in the same folder + + +### installation after release + +> first install the `arduino-cli.exe` and add it to path. verify it using terminal/cmd. + +> then, connect the device and run the app exe. the port selection should have show an entry + +> enter the values and select the port to upload the new dac values for QC + +> the status will be show in the logging box. device will be ready, only if the upload sccuess is shown. \ No newline at end of file diff --git a/hemocube.py b/hemocube.py index d90ab44..523c804 100644 --- a/hemocube.py +++ b/hemocube.py @@ -1,5 +1,136 @@ import sys -from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QPushButton, QLineEdit +from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QPushButton, QLineEdit, QPlainTextEdit, QComboBox, QMessageBox +from PyQt5.QtCore import QProcess, QSize +from everywhereml.arduino import Sketch, Ino, H +import platform +import os + +class LogView(QPlainTextEdit): + def __init__(self, parent=None): + super().__init__(parent) + self.setReadOnly(True) + self._process = QProcess() + self._process.readyReadStandardOutput.connect(self.handle_stdout) + self._process.readyReadStandardError.connect(self.handle_stderr) + + def start_log(self, program, arguments=None): + if arguments is None: + arguments = [] + self._process.start(program, arguments) + + def add_log(self, message): + self.appendPlainText(message.rstrip()) + + def handle_stdout(self): + message = self._process.readAllStandardOutput().data().decode() + self.add_log(message) + + def handle_stderr(self): + message = self._process.readAllStandardError().data().decode() + self.add_log(message) + + +def flash(log_view, led1, led2, port): + """ + Create a sketch object. + A sketch is defined by: + - a name (required) + - a folder (optional) + + If you leave the folder empty, the current working directory will be used. + You can use the special name ':system:' to use the default Arduino sketches folder + (as reported by the command `arduino-cli config dump`) + """ + + showdialog() + + sketch = Sketch(name="hemocube", folder=":system:") + + """ + Then you can add files to the project (either the .ino main file or + C++ header files) + """ + sketch += Ino(""" + +void setup() {{ + // put your setup code here, to run once: + Serial.begin(115200); +}} + +void loop() {{ + // put your main code here, to run repeatedly: + + +}} + + + """.format(led1dac=led1, led2dac=led2)) + + sketch += H("hello.h", """ + void hello() { + Serial.println("hello smi7"); + } + """) + + """ + Compile sketch for Arduino Nano 33 BLE board. + The board you target must appear in the `arduino-cli board listall` command. + If you know the FQBN (Fully Qualified Board Name), you can use that too. + """ + if sketch.compile(board='arduino:avr:nano:cpu=atmega328old').is_successful: + # log_view.add_log("Log: \n\n" + sketch.output) + # log_view.add_log("Sketch stats: \n\n" + sketch.stats) + print('Log', sketch.output) + print('Sketch stats', sketch.stats) + else: + log_view.add_log("ERROR: \n\n" + sketch.output) + print('ERROR', sketch.output) + + """ + You can specify the exact port + """ + # sketch.upload(port='/dev/cu.usbmodem14201') + + sketch.upload(port=port) + + # """ + # Or even part of it. + # The library will look for the best match. + # """ + # sketch.upload(port='ttyUSB') + # sketch.upload(port='/dev/cu.usbserial-1420') #/dev/cu.usbmodem + + log_view.add_log("upload: \n\n" + sketch.output) + print(sketch.output) + +def showdialog(): + msg = QMessageBox() + msg.setIcon(QMessageBox.Information) + + msg.setText("HemoCube flashing") + msg.setInformativeText("HemoCube device will be flashed with new values") + msg.setWindowTitle("Flashing") + msg.setDetailedText("The LED dac values will be set. Wait for sometime.") + msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) + msg.buttonClicked.connect(msgbtn) + + retval = msg.exec_() + print("value of pressed message box button:", retval) + +def msgbtn(i): + print("Button pressed is:",i.text()) + +def get_port(): + ports = [] + if platform.system() == 'Darwin': + ports = list(filter(lambda x: "cu" in x, os.listdir("/dev"))) + else: + import serial.tools.list_ports + # ports = ['COM%s' % (i + 1) for i in range(256)] + serial_ports = list(serial.tools.list_ports.comports()) + for port, desc, hwid in sorted(serial_ports): + ports.append(port) + return ports # 1. Import QApplication and all the required widgets # from PyQt5.QtWidgets import QApplication, QLabel, QWidget @@ -8,33 +139,74 @@ def addLabel(layout, text): layout.addWidget(QLabel(text)) if __name__ == "__main__": - app = QApplication([]) + app = QApplication(sys.argv) - window = QWidget() - layout = QVBoxLayout(window) - # Create a label Widget and add it to the layout - label = QLabel('Enter some text!') - layout.addWidget(label) + window = QWidget() + layout = QVBoxLayout(window) - line_edit = QLineEdit() - layout.addWidget(line_edit) + # Create a label Widget and add it to the layout + labelLed1 = QLabel('Enter LED1 value (1500-3000)') + layout.addWidget(labelLed1) - # Create a QPushButton object with a caption on it - qbtn= QPushButton('Add Label') + line_edit_led1 = QLineEdit() + line_edit_led1.setFixedSize(QSize(150, 30)) + layout.addWidget(line_edit_led1) - # Add the QPushButton to the layout - layout.addWidget(qbtn) + labelLed2 = QLabel('Enter LED2 value (1500-3000)') + left = 0 + top = 25 + right = 0 + bottom = 0 + labelLed2.setContentsMargins(left, top, right, bottom) + layout.addWidget(labelLed2) + + line_edit_led2 = QLineEdit() + line_edit_led2.setFixedSize(QSize(150, 30)) + layout.addWidget(line_edit_led2) + + + labelPort = QLabel('Select a port') + layout.addWidget(labelPort) + + cb = QComboBox() + cb.setFixedSize(QSize(150, 30)) + ports = get_port() + for port in ports: + cb.addItem(port) + layout.addWidget(cb) + + flash_port = "" + def selectionchange(i): + flash_port = cb.currentText() + cb.currentIndexChanged.connect(selectionchange) + + # Create a QPushButton object with a caption on it + qbtn = QPushButton('Flash') + qbtn.setFixedSize(QSize(150, 40)) + + # Add the QPushButton to the layout + layout.addWidget(qbtn) + + w = LogView() + w.resize(640, 480) + # w.show() + # w.start_log("adb", ["logcat", "*:I"]) + # w.start_log("arduino-cli", ["monitor", "-p /dev/cu.Bluetooth-Incoming-Port"]) + # w.start_log("arduino-cli", ["lib", "install", "ADS1X15"]) + w.handle_stdout() + layout.addWidget(w) # Close the application when the button is pressed # Here I am using slots & signals, which I will demonstrate later in this tutorial - qbtn.clicked.connect(lambda:addLabel(layout, line_edit.text())) +# qbtn.clicked.connect(lambda:addLabel(layout, "Flashing...")) + qbtn.clicked.connect(lambda:flash(w, line_edit_led1.text(), line_edit_led2.text(), flash_port)) - window.setWindowTitle("PyQt App") - window.setGeometry(100, 100, 280, 80) - # helloMsg = QLabel("

Hello, World!

", parent=window) - # helloMsg.move(60, 15) + window.setWindowTitle("HemoCube QC") + window.setGeometry(400, 400, 800, 600) + # helloMsg = QLabel("

Hello, World!

", parent=window) + # helloMsg.move(60, 15) - window.show() + window.show() - # 5. Run your application's event loop - sys.exit(app.exec()) + # 5. Run your application's event loop + sys.exit(app.exec()) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..1f23a22 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,56 @@ +altgraph==0.17.3 +cached-property==1.5.2 +certifi==2023.5.7 +charset-normalizer==3.2.0 +contourpy==1.1.0 +cycler==0.11.0 +everywhereml==0.2.21 +fonttools==4.41.0 +hexdump==3.3 +idna==3.4 +imageio==2.31.1 +Jinja2==3.1.2 +jinja2-workarounds==0.1.0 +joblib==1.3.1 +kiwisolver==1.4.4 +lazy_loader==0.3 +llvmlite==0.40.1 +macholib==1.16.2 +MarkupSafe==2.1.3 +matplotlib==3.7.2 +networkx==3.1 +numba==0.57.1 +numpy==1.24.4 +packaging==23.1 +pandas==2.0.3 +pefile==2023.2.7 +Pillow==10.0.0 +pyinstaller==5.13.0 +pyinstaller-hooks-contrib==2023.5 +pynndescent==0.5.10 +pyparsing==3.0.9 +PyQt5==5.15.9 +PyQt5-Qt5==5.15.2 +PyQt5-sip==12.12.1 +PyQt6==6.5.1 +PyQt6-Qt6==6.5.1 +PyQt6-sip==13.5.1 +pyserial==3.5 +python-dateutil==2.8.2 +python-slugify==8.0.1 +pytz==2023.3 +pyudev==0.24.1 +PyWavelets==1.4.1 +requests==2.31.0 +scikit-image==0.21.0 +scikit-learn==1.3.0 +scipy==1.11.1 +seaborn==0.12.2 +six==1.16.0 +text-unidecode==1.3 +threadpoolctl==3.2.0 +tifffile==2023.7.10 +tqdm==4.65.0 +tzdata==2023.3 +umap-learn==0.5.3 +urllib3==2.0.3