From f7758da5201a8c16ddf6ac96e74f1f466445713c Mon Sep 17 00:00:00 2001 From: Laurens Valk Date: Wed, 15 Jan 2025 12:50:00 +0100 Subject: [PATCH] bricks/ev3dev: Goodbye. Thank you, David! Pybricks for ev3dev will continue to be alive and kicking in its original 2.0 form. Since updating to 3.0 and 4.0 is not considered feasible, we are dropping this build to streamline the addition of the upcoming bare metal EV3 port. --- .github/workflows/build.yml | 88 --- .vscode/c_cpp_properties.json | 31 - .vscode/launch.json | 61 -- .vscode/tasks.json | 10 - Makefile | 32 - bricks/_common/mpconfigport.h | 2 +- bricks/_common/sources.mk | 5 - bricks/cityhub/mpconfigport.h | 1 - bricks/debug/mpconfigport.h | 1 - bricks/essentialhub/mpconfigport.h | 1 - bricks/ev3/mpconfigport.h | 1 - bricks/ev3dev/.gitignore | 1 - bricks/ev3dev/Makefile | 333 --------- bricks/ev3dev/README.md | 40 -- bricks/ev3dev/brickconfig.h | 50 -- bricks/ev3dev/docker/README.md | 27 - bricks/ev3dev/docker/armel.dockerfile | 40 -- bricks/ev3dev/docker/setup.sh | 82 --- bricks/ev3dev/ev3dev_mphal.c | 83 --- bricks/ev3dev/ev3dev_mphal.h | 96 --- bricks/ev3dev/manifest.py | 1 - bricks/ev3dev/modbluetooth.c | 81 --- bricks/ev3dev/modmedia_ev3dev.c | 37 - bricks/ev3dev/modules/core.py | 17 - bricks/ev3dev/modules/pybricks/__init__.py | 4 - bricks/ev3dev/modules/pybricks/bluetooth.py | 188 ----- .../ev3dev/modules/pybricks/experimental.py | 88 --- .../ev3dev/modules/pybricks/media/ev3dev.py | 172 ----- bricks/ev3dev/modules/pybricks/messaging.py | 342 --------- bricks/ev3dev/modules/pybricks/nxtdevices.py | 39 - bricks/ev3dev/modules/pybricks/tools.py | 43 -- bricks/ev3dev/modusignal.c | 62 -- bricks/ev3dev/mpconfigport.h | 420 ----------- bricks/ev3dev/mpconfigport.mk | 43 -- bricks/ev3dev/pb_ev3dev_types.h | 31 - bricks/ev3dev/pb_type_ev3dev_font.c | 168 ----- bricks/ev3dev/pb_type_ev3dev_image.c | 581 --------------- bricks/ev3dev/pb_type_ev3dev_speaker.c | 664 ------------------ bricks/ev3dev/pbinit.c | 121 ---- bricks/ev3dev/pbinit.h | 11 - bricks/ev3dev/pbsmbus.c | 156 ---- bricks/ev3dev/pbsmbus.h | 33 - bricks/nxt/mpconfigport.h | 1 - bricks/primehub/mpconfigport.h | 1 - bricks/technichub/mpconfigport.h | 1 - bricks/virtualhub/mpconfigvariant.h | 4 +- .../include/ev3dev_stretch/lego_motor.h | 18 - lib/ev3dev/include/ev3dev_stretch/lego_port.h | 14 - .../include/ev3dev_stretch/lego_sensor.h | 64 -- lib/ev3dev/include/ev3dev_stretch/nxtcolor.h | 14 - lib/ev3dev/include/ev3dev_stretch/sysfs.h | 31 - lib/ev3dev/src/ev3dev_stretch/lego_motor.c | 238 ------- lib/ev3dev/src/ev3dev_stretch/lego_port.c | 193 ----- lib/ev3dev/src/ev3dev_stretch/lego_sensor.c | 307 -------- lib/ev3dev/src/ev3dev_stretch/nxtcolor.c | 537 -------------- lib/ev3dev/src/ev3dev_stretch/sysfs.c | 146 ---- .../drv/counter/counter_ev3dev_stretch_iio.c | 149 ---- lib/pbio/drv/legodev/legodev_ev3dev.c | 211 ------ lib/pbio/drv/legodev/legodev_ev3dev.h | 33 - .../motor_driver_ev3dev_stretch.c | 50 -- .../platform/ev3dev_stretch/contiki-conf.h | 20 - .../platform/ev3dev_stretch/pbdrvconfig.h | 43 -- lib/pbio/platform/ev3dev_stretch/pbioconfig.h | 22 - .../platform/ev3dev_stretch/pbsysconfig.h | 5 - lib/pbio/platform/ev3dev_stretch/platform.c | 38 - .../platform/ev3dev_stretch/status_light.c | 96 --- .../experimental/pb_module_experimental.c | 5 - pybricks/hubs/pb_type_ev3brick.c | 21 - .../pb_type_iodevices_ev3devsensor.c | 116 --- pybricks/nxtdevices/pb_module_nxtdevices.c | 5 - pybricks/pybricks.c | 5 - pybricks/tools/pb_module_tools.c | 5 - pybricks/util_pb/pb_serial.h | 20 - pybricks/util_pb/pb_serial_ev3dev.c | 208 ------ test-ev3dev.sh | 24 - tests/ev3dev/.gitignore | 1 - tests/ev3dev/Makefile | 13 - tests/ev3dev/brick/battery.py | 11 - tests/ev3dev/brick/battery.py.exp | 4 - tests/ev3dev/brick/screen.py | 137 ---- tests/ev3dev/brick/screen.py.exp | 2 - tests/ev3dev/brick/speaker.py | 175 ----- tests/ev3dev/brick/speaker.py.exp | 15 - tests/ev3dev/experimental/thread_tools.py | 48 -- tests/ev3dev/experimental/thread_tools.py.exp | 8 - tests/ev3dev/grx-plugin.c | 90 --- .../lego-ev3-large-motor-port-a.umockdev | 101 --- tests/ev3dev/media/font.py | 45 -- tests/ev3dev/media/font.py.exp | 6 - tests/ev3dev/media/image.py | 238 ------- tests/ev3dev/media/image.py.exp | 18 - tests/ev3dev/media/test.png | Bin 2520 -> 0 bytes tests/ev3dev/messaging/compat.py | 89 --- tests/ev3dev/messaging/compat.py.exp | 15 - tests/ev3dev/motor/motor.py | 79 --- tests/ev3dev/motor/motor.py.exp | 14 - tests/ev3dev/parameters/button.py | 12 - tests/ev3dev/parameters/button.py.exp | 6 - tests/ev3dev/test-wrapper.sh | 9 - tests/ev3dev/tools/matrix.py | 102 --- tests/ev3dev/tools/matrix.py.exp | 99 --- 101 files changed, 2 insertions(+), 8267 deletions(-) delete mode 100644 bricks/ev3dev/.gitignore delete mode 100644 bricks/ev3dev/Makefile delete mode 100644 bricks/ev3dev/README.md delete mode 100644 bricks/ev3dev/brickconfig.h delete mode 100644 bricks/ev3dev/docker/README.md delete mode 100644 bricks/ev3dev/docker/armel.dockerfile delete mode 100755 bricks/ev3dev/docker/setup.sh delete mode 100644 bricks/ev3dev/ev3dev_mphal.c delete mode 100644 bricks/ev3dev/ev3dev_mphal.h delete mode 100644 bricks/ev3dev/manifest.py delete mode 100644 bricks/ev3dev/modbluetooth.c delete mode 100644 bricks/ev3dev/modmedia_ev3dev.c delete mode 100644 bricks/ev3dev/modules/core.py delete mode 100644 bricks/ev3dev/modules/pybricks/__init__.py delete mode 100644 bricks/ev3dev/modules/pybricks/bluetooth.py delete mode 100644 bricks/ev3dev/modules/pybricks/experimental.py delete mode 100644 bricks/ev3dev/modules/pybricks/media/ev3dev.py delete mode 100644 bricks/ev3dev/modules/pybricks/messaging.py delete mode 100644 bricks/ev3dev/modules/pybricks/nxtdevices.py delete mode 100644 bricks/ev3dev/modules/pybricks/tools.py delete mode 100644 bricks/ev3dev/modusignal.c delete mode 100644 bricks/ev3dev/mpconfigport.h delete mode 100644 bricks/ev3dev/mpconfigport.mk delete mode 100644 bricks/ev3dev/pb_ev3dev_types.h delete mode 100644 bricks/ev3dev/pb_type_ev3dev_font.c delete mode 100644 bricks/ev3dev/pb_type_ev3dev_image.c delete mode 100644 bricks/ev3dev/pb_type_ev3dev_speaker.c delete mode 100644 bricks/ev3dev/pbinit.c delete mode 100644 bricks/ev3dev/pbinit.h delete mode 100644 bricks/ev3dev/pbsmbus.c delete mode 100644 bricks/ev3dev/pbsmbus.h delete mode 100644 lib/ev3dev/include/ev3dev_stretch/lego_motor.h delete mode 100644 lib/ev3dev/include/ev3dev_stretch/lego_port.h delete mode 100644 lib/ev3dev/include/ev3dev_stretch/lego_sensor.h delete mode 100644 lib/ev3dev/include/ev3dev_stretch/nxtcolor.h delete mode 100644 lib/ev3dev/include/ev3dev_stretch/sysfs.h delete mode 100644 lib/ev3dev/src/ev3dev_stretch/lego_motor.c delete mode 100644 lib/ev3dev/src/ev3dev_stretch/lego_port.c delete mode 100644 lib/ev3dev/src/ev3dev_stretch/lego_sensor.c delete mode 100644 lib/ev3dev/src/ev3dev_stretch/nxtcolor.c delete mode 100644 lib/ev3dev/src/ev3dev_stretch/sysfs.c delete mode 100644 lib/pbio/drv/counter/counter_ev3dev_stretch_iio.c delete mode 100644 lib/pbio/drv/legodev/legodev_ev3dev.c delete mode 100644 lib/pbio/drv/legodev/legodev_ev3dev.h delete mode 100644 lib/pbio/drv/motor_driver/motor_driver_ev3dev_stretch.c delete mode 100644 lib/pbio/platform/ev3dev_stretch/contiki-conf.h delete mode 100644 lib/pbio/platform/ev3dev_stretch/pbdrvconfig.h delete mode 100644 lib/pbio/platform/ev3dev_stretch/pbioconfig.h delete mode 100644 lib/pbio/platform/ev3dev_stretch/pbsysconfig.h delete mode 100644 lib/pbio/platform/ev3dev_stretch/platform.c delete mode 100644 lib/pbio/platform/ev3dev_stretch/status_light.c delete mode 100644 pybricks/iodevices/pb_type_iodevices_ev3devsensor.c delete mode 100644 pybricks/util_pb/pb_serial.h delete mode 100644 pybricks/util_pb/pb_serial_ev3dev.c delete mode 100755 test-ev3dev.sh delete mode 100644 tests/ev3dev/.gitignore delete mode 100644 tests/ev3dev/Makefile delete mode 100644 tests/ev3dev/brick/battery.py delete mode 100644 tests/ev3dev/brick/battery.py.exp delete mode 100644 tests/ev3dev/brick/screen.py delete mode 100644 tests/ev3dev/brick/screen.py.exp delete mode 100644 tests/ev3dev/brick/speaker.py delete mode 100644 tests/ev3dev/brick/speaker.py.exp delete mode 100644 tests/ev3dev/experimental/thread_tools.py delete mode 100644 tests/ev3dev/experimental/thread_tools.py.exp delete mode 100644 tests/ev3dev/grx-plugin.c delete mode 100644 tests/ev3dev/lego-ev3-large-motor-port-a.umockdev delete mode 100644 tests/ev3dev/media/font.py delete mode 100644 tests/ev3dev/media/font.py.exp delete mode 100644 tests/ev3dev/media/image.py delete mode 100644 tests/ev3dev/media/image.py.exp delete mode 100644 tests/ev3dev/media/test.png delete mode 100644 tests/ev3dev/messaging/compat.py delete mode 100644 tests/ev3dev/messaging/compat.py.exp delete mode 100644 tests/ev3dev/motor/motor.py delete mode 100644 tests/ev3dev/motor/motor.py.exp delete mode 100644 tests/ev3dev/parameters/button.py delete mode 100644 tests/ev3dev/parameters/button.py.exp delete mode 100755 tests/ev3dev/test-wrapper.sh delete mode 100644 tests/ev3dev/tools/matrix.py delete mode 100644 tests/ev3dev/tools/matrix.py.exp diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index de0408705..36af72d30 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -83,94 +83,6 @@ jobs: if: failure() run: micropython/tests/run-tests.py --print-failures - ev3dev_stretch: - name: ev3dev-stretch - runs-on: ubuntu-22.04 - steps: - - name: Docker login - uses: azure/docker-login@v1 - with: - login-server: docker.pkg.github.com - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Install QEMU - run: | - sudo apt-get update - sudo apt-get install qemu-user-static - - name: Checkout repo - uses: actions/checkout@v4 - with: - submodules: true - fetch-depth: 0 - - name: Create docker container - run: bricks/ev3dev/docker/setup.sh armel - - name: Build - run: | - docker exec --tty pybricks-ev3dev_armel make -C ../../micropython/mpy-cross CROSS_COMPILE= - docker exec --tty pybricks-ev3dev_armel make - - name: Test - if: ${{ success() }} - run: | - docker exec --tty pybricks-ev3dev_armel make test-ev3dev - - name: List failed tests - if: failure() - run: micropython/tests/run-tests.py --print-failures - - name: Short hash - id: vars - run: echo "short_sha=$(echo ${{ github.sha }} | cut -c1-8)" >> $GITHUB_OUTPUT - - name: Upload pybricks-micropython - if: ${{ success() }} - uses: actions/upload-artifact@v4 - with: - name: pybricks-micropython-build-${{ github.run_number }}-git${{ steps.vars.outputs.short_sha }} - path: bricks/ev3dev/build-armel/pybricks-micropython - - ev3dev_ubuntu_lts: - name: ev3dev-ubuntu-lts - needs: mpy_cross - runs-on: ubuntu-22.04 - env: - CROSS_COMPILE: "" - steps: - - name: Install rerequisites - run: | - sudo apt-add-repository --update --yes ppa:ev3dev/tools - sudo apt-get install --no-install-recommends --yes \ - alsa-utils \ - espeak \ - ev3dev-media \ - ev3dev-mocks \ - libasound2-plugin-ev3dev \ - libffi-dev \ - libgrx-3.0-dev \ - libi2c-dev \ - libudev-dev \ - libumockdev0 \ - pkg-config \ - uthash-dev \ - xfonts-100dpi - - name: Checkout repo - uses: actions/checkout@v4 - with: - submodules: true - - name: Download mpy-cross - uses: actions/download-artifact@v4 - with: - name: mpy-cross - path: micropython/mpy-cross/build - - name: Fix file permission - run: chmod +x micropython/mpy-cross/build/mpy-cross - - name: Build - run: make $MAKEOPTS -C bricks/ev3dev - - name: Test - if: ${{ success() }} - run: | - make $MAKEOPTS -C bricks/ev3dev test - make $MAKEOPTS -C bricks/ev3dev test-ev3dev - - name: List failed tests - if: failure() - run: micropython/tests/run-tests.py --print-failures - firmware: name: firmware strategy: diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 5a58d5fac..e5f3bce04 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -333,37 +333,6 @@ "cStandard": "c11", "intelliSenseMode": "gcc-arm" }, - { - "name": "ev3dev", - "includePath": [ - "/usr/lib/x86_64-linux-gnu/glib-2.0/include", - "/usr/include/glib-2.0", - "${workspaceFolder}/bricks/ev3dev", - "${workspaceFolder}/bricks/ev3dev/build", - "${workspaceFolder}/lib/contiki-core", - "${workspaceFolder}/lib/ev3dev/include", - "${workspaceFolder}/lib/lego", - "${workspaceFolder}/lib/lwrb/src/include", - "${workspaceFolder}/lib/pbio", - "${workspaceFolder}/lib/pbio/include", - "${workspaceFolder}/lib/pbio/platform/ev3dev_stretch", - "${workspaceFolder}/micropython/ports/unix", - "${workspaceFolder}/micropython", - "${workspaceFolder}" - ], - "defines": [ - "UNIX", - "MICROPY_USE_READLINE=1", - "MICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool", - "MICROPY_MODULE_FROZEN_MPY", - "MPZ_DIG_SIZE=16", - "MICROPY_MODULE_FROZEN_STR" - - ], - "compilerPath": "/usr/bin/gcc", - "cStandard": "c11", - "intelliSenseMode": "gcc-x64" - }, { "name": "virtualhub", "includePath": [ diff --git a/.vscode/launch.json b/.vscode/launch.json index e7f279345..15e0ea03e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -33,14 +33,6 @@ "args": ["${file}", "--show"], "console": "integratedTerminal" }, - { - "name": "Motor Test EV3", - "type": "python", - "request": "launch", - "program": "${workspaceFolder}/tests/motors/run_test.py", - "args": ["${file}", "--target", "ev3dev", "--address", "192.168.133.244", "--show"], - "console": "integratedTerminal" - }, { "name": "Run via USB REPL", "type": "python", @@ -61,44 +53,6 @@ "args": [], "console": "integratedTerminal" }, - { - "name": "ev3dev-test", - "type": "cppdbg", - "request": "launch", - "cwd": "${workspaceFolder}/micropython/tests", - "program": "${workspaceFolder}/bricks/ev3dev/build-test/pybricks-micropython", - "args": [ - "../../tests/ev3dev/brick/battery.py" - ], - "stopAtEntry": false, - "environment": [ - {"name": "GRX_PLUGIN_PATH", "value": "../../bricks/ev3dev/build-test"}, - {"name": "GRX_DRIVER", "value": "test"} - ], - "externalConsole": true, - "MIMode": "gdb", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - }, - { - "description": "ignore SIGUSR1", - "text": "handle SIGUSR1 noprint pass" - }, - { - "description": "ignore SIGUSR2", - "text": "handle SIGUSR2 noprint pass" - }, - { - "description": "ignore SIGRT39", - "text": "handle SIGUSR2 noprint pass" - } - ], - "logging": { "engineLogging": true, "trace": true, "traceResponse": true }, - "preLaunchTask": "build ev3dev-test" - }, { "name": "virtualhub", "type": "cppdbg", @@ -182,21 +136,6 @@ "searchDir": [ "${workspaceRoot}/bricks/debug" ] - }, - { - "name": "(gdb) Attach", - "type": "cppdbg", - "request": "attach", - "program": "${workspaceFolder}/bricks/ev3dev/built-test/pybricks-micropython", - "processId": "${command:pickProcess}", - "MIMode": "gdb", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - } - ] } ], "inputs": [ diff --git a/.vscode/tasks.json b/.vscode/tasks.json index d7244047d..ed24db8a5 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -3,16 +3,6 @@ // for the documentation about the tasks.json format "version": "2.0.0", "tasks": [ - { - "label": "build ev3dev-test", - "type": "shell", - "command": "poetry run make -C bricks/ev3dev build-test/pybricks-micropython build-test/libgrx-3.0-vdriver-test.so DEBUG=1 COPT=-O0 BUILD=build-test CROSS_COMPILE= -j" - }, - { - "label": "build ev3dev deploy", - "type": "shell", - "command": "make ev3dev-armel -j && cp bricks/ev3dev/build-armel/pybricks-micropython /run/user/1000/gvfs/sftp:host=*/home/robot" - }, { "label": "build movehub", "type": "shell", diff --git a/Makefile b/Makefile index 9e8f5a7e0..d302ce53f 100644 --- a/Makefile +++ b/Makefile @@ -32,38 +32,6 @@ all: movehub cityhub technichub primehub essentialhub virtualhub nxt debug ev3 d clean-all: clean-movehub clean-cityhub clean-technichub clean-primehub clean-essentialhub clean-virtualhub clean-nxt clean-debug clean-ev3 clean-doc -ifeq ($(HOST_OS),Linux) - -ev3dev-host: mpy-cross - @$(MAKE) -C bricks/ev3dev CROSS_COMPILE= - -clean-ev3dev-host: clean-mpy-cross - @$(MAKE) -C bricks/ev3dev clean CROSS_COMPILE= - -else - -ev3dev-host: - $(error Building ev3dev for host OS only works on Linux) - -clean-ev3dev-host: ev3dev-host - -endif - -ev3dev-armel: - @if [ ! -d bricks/ev3dev/build-armel/ports ]; then \ - bricks/ev3dev/docker/setup.sh armel; \ - fi - @docker start pybricks-ev3dev_armel - @docker exec --tty pybricks-ev3dev_armel make -C ../../micropython/mpy-cross CROSS_COMPILE= -j`nproc` - @docker exec --tty pybricks-ev3dev_armel make -j`nproc` - -clean-ev3dev-armel: - @if [ -d bricks/ev3dev/build-armel/ports ]; then \ - @docker start pybricks-ev3dev_armel; \ - docker exec --tty pybricks-ev3dev_armel make -C ../../micropython/mpy-cross clean CROSS_COMPILE=; \ - docker exec --tty pybricks-ev3dev_armel make clean; \ - fi - ev3: mpy-cross @$(MAKE) -C bricks/ev3 diff --git a/bricks/_common/mpconfigport.h b/bricks/_common/mpconfigport.h index e4b828ce3..ac741c200 100644 --- a/bricks/_common/mpconfigport.h +++ b/bricks/_common/mpconfigport.h @@ -5,7 +5,7 @@ // REVISIT: This file is still largely focused on embedded MicroPython ports. // Further generalization and possibly a higher option set are needed to use -// this with unix-based ports like the virtual hub or ev3dev. +// this with unix-based ports like the virtual hub. #include #include diff --git a/bricks/_common/sources.mk b/bricks/_common/sources.mk index 1d5430e3e..65e8117f3 100644 --- a/bricks/_common/sources.mk +++ b/bricks/_common/sources.mk @@ -57,7 +57,6 @@ PYBRICKS_PYBRICKS_SRC_C = $(addprefix pybricks/,\ hubs/pb_type_virtualhub.c \ iodevices/pb_module_iodevices.c \ iodevices/pb_type_iodevices_analogsensor.c \ - iodevices/pb_type_iodevices_ev3devsensor.c \ iodevices/pb_type_iodevices_i2cdevice.c \ iodevices/pb_type_iodevices_lwp3device.c \ iodevices/pb_type_iodevices_pupdevice.c \ @@ -107,7 +106,6 @@ PYBRICKS_PYBRICKS_SRC_C = $(addprefix pybricks/,\ util_pb/pb_color_map.c \ util_pb/pb_conversions.c \ util_pb/pb_error.c \ - util_pb/pb_serial_ev3dev.c \ ) # Pybricks I/O library @@ -146,7 +144,6 @@ PBIO_SRC_C = $(addprefix lib/pbio/,\ drv/clock/clock_tiam1808.c \ drv/clock/clock_virtual.c \ drv/core.c \ - drv/counter/counter_ev3dev_stretch_iio.c \ drv/counter/counter_stm32f0_gpio_quad_enc.c \ drv/counter/counter_virtual_cpython.c \ drv/gpio/gpio_stm32f0.c \ @@ -161,14 +158,12 @@ PBIO_SRC_C = $(addprefix lib/pbio/,\ drv/led/led_dual.c \ drv/led/led_pwm.c \ drv/led/led_virtual.c \ - drv/legodev/legodev_ev3dev.c \ drv/legodev/legodev_nxt.c \ drv/legodev/legodev_pup.c \ drv/legodev/legodev_pup_uart.c \ drv/legodev/legodev_spec.c \ drv/legodev/legodev_test.c \ drv/legodev/legodev_virtual.c \ - drv/motor_driver/motor_driver_ev3dev_stretch.c \ drv/motor_driver/motor_driver_hbridge_pwm.c \ drv/motor_driver/motor_driver_nxt.c \ drv/motor_driver/motor_driver_virtual_cpython.c \ diff --git a/bricks/cityhub/mpconfigport.h b/bricks/cityhub/mpconfigport.h index 43296917c..29e7d8ff2 100644 --- a/bricks/cityhub/mpconfigport.h +++ b/bricks/cityhub/mpconfigport.h @@ -32,7 +32,6 @@ #define PYBRICKS_PY_IODEVICES (1) #define PYBRICKS_PY_IODEVICES_XBOX_CONTROLLER (0) #define PYBRICKS_PY_MEDIA (0) -#define PYBRICKS_PY_MEDIA_EV3DEV (0) #define PYBRICKS_PY_NXTDEVICES (0) #define PYBRICKS_PY_PARAMETERS (1) #define PYBRICKS_PY_PARAMETERS_BUTTON (1) diff --git a/bricks/debug/mpconfigport.h b/bricks/debug/mpconfigport.h index 060f747bd..a92f6628e 100644 --- a/bricks/debug/mpconfigport.h +++ b/bricks/debug/mpconfigport.h @@ -28,7 +28,6 @@ #define PYBRICKS_PY_HUBS (0) #define PYBRICKS_PY_IODEVICES (0) #define PYBRICKS_PY_MEDIA (0) -#define PYBRICKS_PY_MEDIA_EV3DEV (0) #define PYBRICKS_PY_NXTDEVICES (0) #define PYBRICKS_PY_PARAMETERS (1) #define PYBRICKS_PY_PARAMETERS_BUTTON (1) diff --git a/bricks/essentialhub/mpconfigport.h b/bricks/essentialhub/mpconfigport.h index 5708460d6..6682adb4d 100644 --- a/bricks/essentialhub/mpconfigport.h +++ b/bricks/essentialhub/mpconfigport.h @@ -33,7 +33,6 @@ #define PYBRICKS_PY_IODEVICES (1) #define PYBRICKS_PY_IODEVICES_XBOX_CONTROLLER (1) #define PYBRICKS_PY_MEDIA (0) -#define PYBRICKS_PY_MEDIA_EV3DEV (0) #define PYBRICKS_PY_NXTDEVICES (0) #define PYBRICKS_PY_PARAMETERS (1) #define PYBRICKS_PY_PARAMETERS_BUTTON (1) diff --git a/bricks/ev3/mpconfigport.h b/bricks/ev3/mpconfigport.h index 58328517c..f4fec458d 100644 --- a/bricks/ev3/mpconfigport.h +++ b/bricks/ev3/mpconfigport.h @@ -30,7 +30,6 @@ #define PYBRICKS_PY_HUBS (1) #define PYBRICKS_PY_IODEVICES (0) #define PYBRICKS_PY_MEDIA (0) -#define PYBRICKS_PY_MEDIA_EV3DEV (0) #define PYBRICKS_PY_NXTDEVICES (1) #define PYBRICKS_PY_PARAMETERS (1) #define PYBRICKS_PY_PARAMETERS_BUTTON (1) diff --git a/bricks/ev3dev/.gitignore b/bricks/ev3dev/.gitignore deleted file mode 100644 index ed6c23608..000000000 --- a/bricks/ev3dev/.gitignore +++ /dev/null @@ -1 +0,0 @@ -pybricks-micropython diff --git a/bricks/ev3dev/Makefile b/bricks/ev3dev/Makefile deleted file mode 100644 index b06c47b6c..000000000 --- a/bricks/ev3dev/Makefile +++ /dev/null @@ -1,333 +0,0 @@ -# SPDX-License-Identifier: MIT -# Copyright (c) 2013, 2014 Damien P. George -# Copyright (c) 2019-2023 The Pybricks Authors - -# ensure required git submodules checked out -ifeq ("$(wildcard ../../micropython/README.md)","") -$(info GIT cloning micropython submodule) -$(info $(shell cd ../.. && git submodule update --init micropython)) -ifeq ("$(wildcard ../../micropython/README.md)","") -$(error failed) -endif -endif -ifeq ("$(wildcard ../../micropython/lib/axtls/README)","") -$(info GIT cloning axtls submodule) -$(info $(shell cd ../../micropython && git submodule update --init lib/axtls)) -ifeq ("$(wildcard ../../micropython/lib/axtls/README)","") -$(error failed) -endif -endif -ifeq ("$(wildcard ../../micropython/lib/berkeley-db-1.xx/README)","") -$(info GIT cloning berkeley-db-1.xx submodule) -$(info $(shell cd ../../micropython && git submodule update --init lib/berkeley-db-1.xx)) -ifeq ("$(wildcard ../../micropython/lib/berkeley-db-1.xx/README)","") -$(error failed) -endif -endif -ifeq ("$(wildcard ../../micropython/lib/micropython-lib/README.md)","") -$(info GIT cloning micropython-lib submodule) -$(info $(shell cd ../../micropython && git submodule update --init lib/micropython-lib)) -ifeq ("$(wildcard ../../micropython/lib/micropython-lib/README.md)","") -$(error failed) -endif -endif - -# lets micropython make files work with external files -USER_C_MODULES = ../.. - -# Environment --include mpconfigport.mk -include ../../micropython/py/mkenv.mk - -# Frozen Python code -FROZEN_MANIFEST ?= manifest.py - -# define main target -PROG = pybricks-micropython - -# qstr definitions (must come before including py.mk) -QSTR_DEFS = ../_common/qstrdefs.h -QSTR_GLOBAL_DEPENDENCIES = brickconfig.h - -# OS name, for simple autoconfig -UNAME_S := $(shell uname -s) - -# include py core make definitions -include $(TOP)/py/py.mk -include $(TOP)/extmod/extmod.mk - -INC += -I. -INC += -I$(TOP) -INC += -I$(BUILD) -INC += -I../../lib/contiki-core -INC += -I../../lib/ev3dev -INC += -I../../lib/ev3dev/include -INC += -I../../lib/lego -INC += -I../../lib/pbio -INC += -I../../lib/pbio/include -INC += -I../../lib/pbio/platform/ev3dev_stretch -INC += -I../.. -INC += -I$(TOP)/ports/unix - -# compiler settings -CFLAGS_WARN = -Wall -Werror -Wextra -Wno-unused-parameter -Wno-maybe-uninitialized -CFLAGS_WARN += -Wpointer-arith -Wdouble-promotion -Wfloat-conversion -CFLAGS += $(INC)-std=gnu99 -DUNIX $(CFLAGS_WARN) $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA) - -# Debugging/Optimization -ifdef DEBUG -COPT ?= -Og -else -COPT ?= -Os -COPT += -DNDEBUG -endif - -# Remove unused sections. -COPT += -fdata-sections -ffunction-sections - -# Always enable symbols -- They're occasionally useful, and don't make it into the -# final .bin/.hex/.dfu so the extra size doesn't matter. -CFLAGS += -g - -ifndef DEBUG -# _FORTIFY_SOURCE is a feature in gcc/glibc which is intended to provide extra -# security for detecting buffer overflows. Some distros (Ubuntu at the very least) -# have it enabled by default. -# -# gcc already optimizes some printf calls to call puts and/or putchar. When -# _FORTIFY_SOURCE is enabled and compiling with -O1 or greater, then some -# printf calls will also be optimized to call __printf_chk (in glibc). Any -# printfs which get redirected to __printf_chk are then no longer synchronized -# with printfs that go through mp_printf. -# -# In MicroPython, we don't want to use the runtime library's printf but rather -# go through mp_printf, so that stdout is properly tied into streams, etc. -# This means that we either need to turn off _FORTIFY_SOURCE or provide our -# own implementation of __printf_chk. We've chosen to turn off _FORTIFY_SOURCE. -# It should also be noted that the use of printf in MicroPython is typically -# quite limited anyways (primarily for debug and some error reporting, etc -# in the unix version). -# -# Information about _FORTIFY_SOURCE seems to be rather scarce. The best I could -# find was this: https://securityblog.redhat.com/2014/03/26/fortify-and-you/ -# Original patchset was introduced by -# https://gcc.gnu.org/ml/gcc-patches/2004-09/msg02055.html . -# -# Turning off _FORTIFY_SOURCE is only required when compiling with -O1 or greater -CFLAGS += -U _FORTIFY_SOURCE -endif - -# On OSX, 'gcc' is a symlink to clang unless a real gcc is installed. -# The unix port of MicroPython on OSX must be compiled with clang, -# while cross-compile ports require gcc, so we test here for OSX and -# if necessary override the value of 'CC' set in py/mkenv.mk -ifeq ($(UNAME_S),Darwin) -ifeq ($(MICROPY_FORCE_32BIT),1) -CC = clang -m32 -else -CC = clang -endif -# Use clang syntax for map file -LDFLAGS_ARCH = -Wl,-map,$@.map -Wl,-dead_strip -else -# Use gcc syntax for map file -LDFLAGS_ARCH = -Wl,-Map=$@.map,--cref -Wl,--gc-sections -endif -LDFLAGS += $(LDFLAGS_MOD) $(LDFLAGS_ARCH) -lm $(LDFLAGS_EXTRA) - -# Flags to link with pthread library -LDFLAGS += -lpthread - -ifeq ($(MICROPY_USE_READLINE),1) -INC += -I$(TOP)/shared/readline -CFLAGS_MOD += -DMICROPY_USE_READLINE=1 -SHARED_SRC_C_EXTRA += readline/readline.c -endif -ifeq ($(MICROPY_PY_TERMIOS),1) -CFLAGS_MOD += -DMICROPY_PY_TERMIOS=1 -SRC_MOD += ports/unix/modtermios.c -endif -ifeq ($(MICROPY_PY_SOCKET),1) -CFLAGS_MOD += -DMICROPY_PY_SOCKET=1 -SRC_MOD += ports/unix/modusocket.c -endif - -ifeq ($(MICROPY_PY_FFI),1) -LIBFFI_CFLAGS_MOD := $(shell pkg-config --cflags libffi) -LIBFFI_LDFLAGS_MOD := $(shell pkg-config --libs libffi) - -ifeq ($(UNAME_S),Linux) -LIBFFI_LDFLAGS_MOD += -ldl -endif - -CFLAGS_MOD += $(LIBFFI_CFLAGS_MOD) -DMICROPY_PY_FFI=1 -LDFLAGS_MOD += $(LIBFFI_LDFLAGS_MOD) -SRC_MOD += ports/unix/modffi.c -endif - -ifeq ($(MICROPY_PY_JNI),1) -# Path for 64-bit OpenJDK, should be adjusted for other JDKs -CFLAGS_MOD += -I/usr/lib/jvm/java-7-openjdk-amd64/include -DMICROPY_PY_JNI=1 -SRC_MOD += ports/unix/modjni.c -endif - -CFLAGS_MOD += $(shell pkg-config --cflags libudev) -LDFLAGS_MOD += $(shell pkg-config --libs libudev) - -CFLAGS_MOD += $(shell pkg-config --cflags glib-2.0) -LDFLAGS_MOD += $(shell pkg-config --libs glib-2.0) - -CFLAGS_MOD += $(shell pkg-config --cflags gio-2.0) -LDFLAGS_MOD += $(shell pkg-config --libs gio-2.0) - -CFLAGS_MOD += $(shell pkg-config --cflags grx-3.0) -LDFLAGS_MOD += $(shell pkg-config --libs grx-3.0) - -# for pbsmbus -ifneq ($(shell $(CC) -print-file-name=libi2c.a),libi2c.a) -# in i2ctools v4, there is an acutal library and the header file has moved -CFLAGS_MOD += -DPB_HAVE_LIBI2C=1 -LDFLAGS_MOD += -li2c -endif - -# Sources and libraries common to all pybricks bricks -PBIO_PLATFORM = ev3dev_stretch - -include ../_common/sources.mk - -# Extra core MicroPython files - -# NB: Since we are using MicroPython's build system, files in the micropython/ -# directory have the micropython/ prefix excluded. It is very important to do -# it that way since there is special handling of certain files that will break -# if we don't do it this way. So we need to be very careful about name clashes -# between the top level directory and the micropython/ subdirectory. - -PY_EXTRA_SRC_C += $(addprefix ports/unix/,\ - alloc.c \ - coverage.c \ - gccollect.c \ - input.c \ - main.c \ - modmachine.c \ - modtime.c \ - modufcntl.c \ - modummap.c \ - moduselect.c \ - mpthreadport.c \ - unix_mphal.c \ - ) - -SRC_C += $(SRC_MOD) - -SHARED_SRC_C += $(addprefix shared/,\ - runtime/gchelper_generic.c \ - timeutils/timeutils.c \ - $(SHARED_SRC_C_EXTRA) \ - ) - -SRC_CXX += \ - -# Pybricks port core source files -PYBRICKS_SRC_C += \ - ev3dev_mphal.c \ - modbluetooth.c \ - modusignal.c \ - modmedia_ev3dev.c \ - pb_type_ev3dev_font.c \ - pb_type_ev3dev_image.c \ - pb_type_ev3dev_speaker.c \ - pbinit.c \ - pbsmbus.c \ - - -EV3DEV_LIB_SRC_C = $(addprefix lib/,\ - ev3dev/src/ev3dev_stretch/lego_motor.c \ - ev3dev/src/ev3dev_stretch/lego_port.c \ - ev3dev/src/ev3dev_stretch/lego_sensor.c \ - ev3dev/src/ev3dev_stretch/nxtcolor.c \ - ev3dev/src/ev3dev_stretch/sysfs.c \ - pbio/platform/ev3dev_stretch/status_light.c \ - ) - -OBJ = $(PY_O) -OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(SRC_CXX:.cpp=.o)) -OBJ += $(addprefix $(BUILD)/, $(SHARED_SRC_C:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(CONTIKI_SRC_C:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(EV3DEV_LIB_SRC_C:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(SRC_EXTMOD_C:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(PBIO_SRC_C:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(PY_EXTRA_SRC_C:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(PYBRICKS_PYBRICKS_SRC_C:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(PYBRICKS_SRC_C:.c=.o)) - -# List of sources for qstr extraction -SRC_QSTR += $(SRC_C) $(SHARED_SRC_C) $(PY_EXTRA_SRC_C) $(SRC_EXTMOD_C) $(PYBRICKS_SRC_C) $(PYBRICKS_PYBRICKS_SRC_C) -# Append any auto-generated sources that are needed by sources listed in -# SRC_QSTR -SRC_QSTR_AUTO_DEPS += - -ifneq ($(FROZEN_MANIFEST),) -# To use frozen code create a manifest.py file with a description of files to -# freeze, then invoke make with FROZEN_MANIFEST=manifest.py (be sure to build from scratch). -CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool -CFLAGS += -DMICROPY_MODULE_FROZEN_MPY -CFLAGS += -DMPZ_DIG_SIZE=16 # force 16 bits to work on both 32 and 64 bit archs -CFLAGS += -DMICROPY_MODULE_FROZEN_STR -endif - -include $(TOP)/py/mkrules.mk - -.PHONY: test - -EV3DEV_TEST_DIRS = $(addprefix ../../tests/ev3dev/, \ - brick \ - experimental \ - geometry \ - media \ - messaging \ - motor \ - parameters \ - ) - -GRX_TEST_PLUGIN_OBJ := $(BUILD)/grx-plugin.o -GRX_TEST_PLUGIN_LIB := $(BUILD)/libgrx-3.0-vdriver-test.so - -$(GRX_TEST_PLUGIN_OBJ): ../../tests/ev3dev/grx-plugin.c - $(Q)$(CC) -c -fPIC -o $@ $^ $(CFLAGS) - -$(GRX_TEST_PLUGIN_LIB): $(GRX_TEST_PLUGIN_OBJ) - $(Q)$(CC) -shared -o $@ $^ $(LDFLAGS) - -test-ev3dev: $(BUILD)/$(PROG) $(TOP)/tests/run-tests.py $(GRX_TEST_PLUGIN_LIB) - cd $(TOP)/tests && PYBRICKS_MICROPYTHON="$(realpath $<)" MICROPY_MICROPYTHON="../../tests/ev3dev/test-wrapper.sh" \ - GRX_PLUGIN_PATH=$(realpath $(BUILD)) GRX_DRIVER=test \ - ./run-tests.py --test-dirs $(EV3DEV_TEST_DIRS) - -test: $(BUILD)/$(PROG) $(TOP)/tests/run-tests.py $(GRX_TEST_PLUGIN_LIB) - $(eval DIRNAME=../bricks/$(notdir $(CURDIR))) - cd $(TOP)/tests && PYBRICKS_MICROPYTHON="$(realpath $<)" MICROPY_MICROPYTHON="../../tests/ev3dev/test-wrapper.sh" \ - GRX_PLUGIN_PATH=$(realpath $(BUILD)) GRX_DRIVER=test \ - ./run-tests.py - -repl: $(BUILD)/$(PROG) $(GRX_TEST_PLUGIN_LIB) modules/core.py - GRX_PLUGIN_PATH=$(realpath $(BUILD)) GRX_DRIVER=test $< -i modules/core.py - -# Value of configure's --host= option (required for cross-compilation). -# Deduce it from CROSS_COMPILE by default, but can be overridden. -ifneq ($(CROSS_COMPILE),) -CROSS_COMPILE_HOST = --host=$(patsubst %-,%,$(CROSS_COMPILE)) -else -CROSS_COMPILE_HOST = -endif - -PREFIX = /usr/local -BINDIR = $(DESTDIR)$(PREFIX)/bin - -install: $(BUILD)/$(PROG) - install -d $(BINDIR) - install $(BUILD)/$(PROG) $(BINDIR)/$(PROG) - -uninstall: - -rm $(BINDIR)/$(PROG) diff --git a/bricks/ev3dev/README.md b/bricks/ev3dev/README.md deleted file mode 100644 index e85b0d224..000000000 --- a/bricks/ev3dev/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Pybricks for EV3 - -## Building - -See the [docker](./docker) folder for build instructions. - -## Development tricks for Ubuntu - -The following tips can help speed up development on Ubuntu. - -Once connected, you can mount the robot file system locally for easy access: - -``` -gio mount ssh://robot@192.168.133.101/home/robot -``` - -Run the following on the brick once after preparing the microSD card. - -``` -rm -f pybricks-micropython -touch pybricks-micropython -chmod +x pybricks-micropython -sudo rm -f /usr/bin/pybricks-micropython -sudo ln -s /home/robot/pybricks-micropython /usr/bin/pybricks-micropython -``` - -Once you've followed the steps above, you can build and deploy using: - -``` -make ev3dev-armel && cp bricks/ev3dev/build-armel/pybricks-micropython /run/user/1000/gvfs/sftp:host=*,user=robot/home/robot -``` - -Then all pybricks-micropython tools and projects will use the new build without -requiring further modifications in the project. - -Start Pybricks and run commands to initialize it for easy testing: - -``` -brickrun --redirect -- pybricks-micropython -i -c "from core import *; print('add even more init here')" -``` diff --git a/bricks/ev3dev/brickconfig.h b/bricks/ev3dev/brickconfig.h deleted file mode 100644 index a982a3518..000000000 --- a/bricks/ev3dev/brickconfig.h +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2018-2023 The Pybricks Authors - -#include -#include "pbinit.h" - -#define MICROPY_HW_BOARD_NAME "LEGO MINDSTORMS EV3 Intelligent Brick" -#define MICROPY_HW_MCU_NAME "Texas Instruments AM1808" - -#define PYBRICKS_HUB_NAME "ev3" -#define PYBRICKS_HUB_CLASS_NAME (MP_QSTR_EV3Brick) -#define PYBRICKS_HUB_EV3BRICK (1) - -// In this port, Pybricks runs on top of ev3dev. -#define PYBRICKS_RUNS_ON_EV3DEV (1) - -// Pybricks modules -#define PYBRICKS_PY_COMMON (1) -#define PYBRICKS_PY_COMMON_BLE (0) -#define PYBRICKS_PY_COMMON_CHARGER (0) -#define PYBRICKS_PY_COMMON_COLOR_LIGHT (1) -#define PYBRICKS_PY_COMMON_CONTROL (1) -#define PYBRICKS_PY_COMMON_IMU (0) -#define PYBRICKS_PY_COMMON_KEYPAD (1) -#define PYBRICKS_PY_COMMON_KEYPAD_HUB_BUTTONS (6) -#define PYBRICKS_PY_COMMON_LIGHT_ARRAY (0) -#define PYBRICKS_PY_COMMON_LIGHT_MATRIX (0) -#define PYBRICKS_PY_COMMON_LOGGER (1) -#define PYBRICKS_PY_COMMON_LOGGER_REAL_FILE (1) -#define PYBRICKS_PY_COMMON_MOTOR_MODEL (1) -#define PYBRICKS_PY_COMMON_MOTORS (1) -#define PYBRICKS_PY_COMMON_SPEAKER (0) -#define PYBRICKS_PY_COMMON_SYSTEM (1) -#define PYBRICKS_PY_EV3DEVICES (1) -#define PYBRICKS_PY_EXPERIMENTAL (1) -#define PYBRICKS_PY_HUBS (1) -#define PYBRICKS_PY_IODEVICES (1) -#define PYBRICKS_PY_MEDIA (0) -#define PYBRICKS_PY_MEDIA_EV3DEV (1) -#define PYBRICKS_PY_NXTDEVICES (1) -#define PYBRICKS_PY_PARAMETERS (1) -#define PYBRICKS_PY_PARAMETERS_BUTTON (1) -#define PYBRICKS_PY_PARAMETERS_ICON (0) -#define PYBRICKS_PY_DEVICES (1) -#define PYBRICKS_PY_ROBOTICS (1) -#define PYBRICKS_PY_ROBOTICS_DRIVEBASE_SPIKE (0) -#define PYBRICKS_PY_TOOLS (1) -#define PYBRICKS_PY_TOOLS_HUB_MENU (0) -#define PYBRICKS_PY_TOOLS_APP_DATA (0) -#define PYBRICKS_PY_USIGNAL (1) diff --git a/bricks/ev3dev/docker/README.md b/bricks/ev3dev/docker/README.md deleted file mode 100644 index 608853d2b..000000000 --- a/bricks/ev3dev/docker/README.md +++ /dev/null @@ -1,27 +0,0 @@ -Using Docker to Cross-Compile Pybricks MicroPython for ev3dev -------------------------------------------------------------- - -This assumes that you have already `docker` installed and that you have cloned -our [MicroPython fork](https://github.com/pybricks/micropython) and its -submodules and have built `mpy-cross` for the host OS (`make -C mpy-cross`). - -1. Create the docker image and a docker container. - - bricks/ev3dev/docker/setup.sh armel - -2. Cross compile MicroPython. - - docker exec --tty pybricks-ev3dev_armel make - -3. Transfer the generated `pybricks-micropython` to the EV3 Brick. - - scp bricks/ev3dev/build-armel/pybricks-micropython robot@ev3dev:~ - -4. Run it on the EV3. - - ssh -t robot@ev3dev "brickrun -r -- ./pybricks-micropython" - - -If local changes are made to the dockerfile, the image can be rebuilt with: - - bricks/ev3dev/docker/setup.sh armel rebuild diff --git a/bricks/ev3dev/docker/armel.dockerfile b/bricks/ev3dev/docker/armel.dockerfile deleted file mode 100644 index 5f6480496..000000000 --- a/bricks/ev3dev/docker/armel.dockerfile +++ /dev/null @@ -1,40 +0,0 @@ -FROM ev3dev/debian-stretch-cross -RUN sudo apt-get update && \ - DEBIAN_FRONTEND=noninteractive sudo apt-get install --yes --no-install-recommends \ - alsa-utils \ - build-essential \ - espeak \ - ev3dev-media \ - ev3dev-mocks \ - git \ - libasound2-plugin-ev3dev \ - libasound2-plugin-ev3dev:armel \ - libasound2:armel \ - libc6-dbg:armel \ - libffi-dev:armel \ - libglib2.0-0-dbg:armel \ - libgrx-3.0-2-dbgsym:armel \ - libgrx-3.0-dev:armel \ - libi2c-dev \ - libudev-dev:armel \ - libumockdev0:armel \ - pkg-config \ - python \ - python3 \ - uthash-dev:armel \ - xfonts-100dpi -RUN apt-get download umockdev:armel && \ - ar x umockdev*.deb data.tar.xz && \ - sudo tar -C / -xf data.tar.xz ./usr/lib/arm-linux-gnueabi/libumockdev-preload.so.0.0.0 && \ - sudo tar -C / -xf data.tar.xz ./usr/lib/arm-linux-gnueabi/libumockdev-preload.so.0 && \ - rm data.tar.xz && rm *.deb -# Hack to get correct linux/i2c-dev.h header file in cross compiler -# Kernel version of i2c-dev.h is in /usr/arm-linux-gnueabi/include/ which is first in search path -# thanks https://stackoverflow.com/a/36287466/1976323 -RUN sudo mv /usr/arm-linux-gnueabi/include/linux/i2c-dev.h /usr/arm-linux-gnueabi/include/linux/i2c-dev.h.kernel && \ - sudo cp /usr/include/linux/i2c-dev.h /usr/arm-linux-gnueabi/include/linux/i2c-dev.h -RUN sudo rm /etc/fonts/conf.d/70-no-bitmaps.conf -ENV PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabi/pkgconfig -ENV CROSS_COMPILE=arm-linux-gnueabi- -ENV BUILD=build-armel -ENV PYBRICKS_BUILD_ENV=docker-armel diff --git a/bricks/ev3dev/docker/setup.sh b/bricks/ev3dev/docker/setup.sh deleted file mode 100755 index efa9a2693..000000000 --- a/bricks/ev3dev/docker/setup.sh +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/bash - -set -e - -project="pybricks-ev3dev" - -abs_path() { - # https://stackoverflow.com/a/3915420/1976323 - echo "$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")" -} - -real_path() { - # for Cygwin, get Windows path, otherwise pass through unchanged - if [ "$(uname -s | cut -b-9)" == "CYGWIN_NT" ]; then - echo "$(cygpath -w "$1")" - else - echo "$1" - fi -} - -script_dir=$(dirname $(abs_path "${0}")) - -case ${1} in - armel) - arch=${1} - ;; - *) - echo "Error: Must specify 'armel'" - exit 1 - ;; -esac - -if ! which docker >/dev/null; then - echo "Error: Docker is not installed" - exit 1 -fi - -src_dir="${script_dir}/../../.." -build_dir="${script_dir}/../build-${arch}" -image_name="docker.pkg.github.com/pybricks/pybricks-micropython/${project}-${arch}:latest" -container_name="${project}_${arch}" - -if [ -e ${build_dir} ]; then - read -r -n 1 -p "Delete existing build directory at '$(real_path ${build_dir})'? (y/n/q) " - echo - case $REPLY in - y|Y) - rm -rf "${build_dir}" - ;; - q|Q) - exit 0 - ;; - *) - ;; - esac -fi -mkdir -p ${build_dir} - -if [ "${2}" == "rebuild" ]; then - docker build \ - --tag "${image_name}" \ - --no-cache \ - --file "${script_dir}/${arch}.dockerfile" \ - "${script_dir}/" -else - docker pull "${image_name}" -fi - -docker rm --force ${container_name} >/dev/null 2>&1 || true -docker run \ - --volume "$(real_path ${src_dir}):/src" \ - --workdir /src/bricks/ev3dev \ - --name ${container_name} \ - --env "TERM=${TERM}" \ - --env "DESTDIR=/build/dist" \ - --env "MICROPY_MPYCROSS=/src/micropython/mpy-cross/build-armel/mpy-cross" \ - --user $(id -u):$(id -g) \ - --tty \ - --detach \ - ${image_name} tail - -echo "Done. You can now compile by running 'docker exec --tty ${container_name} make'" diff --git a/bricks/ev3dev/ev3dev_mphal.c b/bricks/ev3dev/ev3dev_mphal.c deleted file mode 100644 index ecb840a13..000000000 --- a/bricks/ev3dev/ev3dev_mphal.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2015 Damien P. George - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include - -#include "py/mphal.h" -#include "py/runtime.h" -#include "py/stream.h" - -void mp_hal_stdout_tx_flush(void) { - // currently not buffered -} - -void pb_ev3dev_hal_delay_ms(mp_uint_t ms) { - struct timespec ts = { - .tv_sec = ms / 1000, - .tv_nsec = ms % 1000 * 1000000, - }; - struct timespec remain; - for (;;) { - mp_handle_pending(true); - MP_THREAD_GIL_EXIT(); - int ret = clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, &remain); - MP_THREAD_GIL_ENTER(); - if (ret == EINTR) { - ts = remain; - continue; - } - assert(ret == 0); - break; - } -} - -uintptr_t mp_hal_stdio_poll(uintptr_t flags) { - struct pollfd fds[] = { - { .fd = STDIN_FILENO, .events = flags & MP_STREAM_POLL_RD ? POLLIN : 0, }, - { .fd = STDOUT_FILENO, .events = flags & MP_STREAM_POLL_WR ? POLLOUT : 0, }, - }; - int ret; - - MP_HAL_RETRY_SYSCALL(ret, poll(fds, MP_ARRAY_SIZE(fds), 0), mp_raise_OSError(err)); - - uintptr_t rflags = 0; - - if (ret > 0) { - if (fds[0].revents & POLLIN) { - rflags |= MP_STREAM_POLL_RD; - } - if (fds[1].revents & POLLOUT) { - rflags |= MP_STREAM_POLL_WR; - } - } - - return rflags; -} diff --git a/bricks/ev3dev/ev3dev_mphal.h b/bricks/ev3dev/ev3dev_mphal.h deleted file mode 100644 index 70ab94d6b..000000000 --- a/bricks/ev3dev/ev3dev_mphal.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2015 Damien P. George - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include -#include - -#ifndef CHAR_CTRL_C -#define CHAR_CTRL_C (3) -#endif - -void mp_hal_set_interrupt_char(char c); - -void mp_hal_stdio_mode_raw(void); -void mp_hal_stdio_mode_orig(void); - -#if MICROPY_USE_READLINE == 1 && MICROPY_PY_BUILTINS_INPUT -#include "py/misc.h" -#include "shared/readline/readline.h" -// For built-in input() we need to wrap the standard readline() to enable raw mode -#define mp_hal_readline mp_hal_readline -static inline int mp_hal_readline(vstr_t *vstr, const char *p) { - mp_hal_stdio_mode_raw(); - int ret = readline(vstr, p); - mp_hal_stdio_mode_orig(); - return ret; -} -#endif - -#define mp_hal_delay_ms(ms) do { \ - void pb_ev3dev_hal_delay_ms(mp_uint_t); \ - pb_ev3dev_hal_delay_ms(ms); \ -} while (0) - -// TODO: POSIX et al. define usleep() as guaranteedly capable only of 1s sleep: -// "The useconds argument shall be less than one million." -static inline void mp_hal_delay_us(mp_uint_t us) { - usleep(us); -} - -#define mp_hal_ticks_cpu() 0 - -#define mp_hal_ticks_ms() ((mp_uint_t)({ \ - uint32_t pbdrv_clock_get_ms(void); \ - pbdrv_clock_get_ms(); \ - })) - -#define mp_hal_ticks_us() ((mp_uint_t)({ \ - uint32_t pbdrv_clock_get_us(void); \ - pbdrv_clock_get_us(); \ - })) - -void mp_hal_get_random(size_t n, void *buf); - -#define RAISE_ERRNO(err_flag, error_val) \ - { if (err_flag == -1) \ - { mp_raise_OSError(error_val); } } - -// This macro is used to implement PEP 475 to retry specified syscalls on EINTR -#define MP_HAL_RETRY_SYSCALL(ret, syscall, raise) { \ - for (;;) { \ - MP_THREAD_GIL_EXIT(); \ - ret = syscall; \ - MP_THREAD_GIL_ENTER(); \ - if (ret == -1) { \ - int err = errno; \ - if (err == EINTR) { \ - mp_handle_pending(true); \ - continue; \ - } \ - raise; \ - } \ - break; \ - } \ -} diff --git a/bricks/ev3dev/manifest.py b/bricks/ev3dev/manifest.py deleted file mode 100644 index 8dd552435..000000000 --- a/bricks/ev3dev/manifest.py +++ /dev/null @@ -1 +0,0 @@ -freeze_as_mpy("./modules") diff --git a/bricks/ev3dev/modbluetooth.c b/bricks/ev3dev/modbluetooth.c deleted file mode 100644 index 30de6514f..000000000 --- a/bricks/ev3dev/modbluetooth.c +++ /dev/null @@ -1,81 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2020 The Pybricks Authors - -#include -#include - -#include "py/mpconfig.h" - -#include "py/obj.h" -#include "py/runtime.h" - - -// Gets the Bluetooth address for a paired device. name_in can be device name -// or Bluetooth address. This is intended to be somewhat equivelent to -// socket.gethostbyname() for IPv4 addresses. -static mp_obj_t ev3dev_bluetooth_resolve(mp_obj_t name_in) { - const char *name_str = mp_obj_str_get_str(name_in); - GError *error = NULL; - MP_THREAD_GIL_EXIT(); - GDBusObjectManager *object_manager = g_dbus_object_manager_client_new_for_bus_sync( - G_BUS_TYPE_SYSTEM, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, - "org.bluez", "/", NULL, NULL, NULL, NULL, &error); - MP_THREAD_GIL_ENTER(); - if (!object_manager) { - mp_obj_t ex = mp_obj_new_exception_msg_varg(&mp_type_RuntimeError, "%s", error->message); - g_error_free(error); - nlr_raise(ex); - } - - mp_obj_t match = mp_const_none; - GList *objects = g_dbus_object_manager_get_objects(object_manager); - for (GList *o = objects; o != NULL; o = o->next) { - GDBusObject *obj = G_DBUS_OBJECT(o->data); - GDBusProxy *device = G_DBUS_PROXY(g_dbus_object_get_interface(obj, "org.bluez.Device1")); - if (!device) { - continue; - } - GVariant *paired_v = g_dbus_proxy_get_cached_property(device, "Paired"); - gboolean paired = g_variant_get_boolean(paired_v); - g_variant_unref(paired_v); - if (!paired) { - g_object_unref(device); - continue; - } - - GVariant *address_v = g_dbus_proxy_get_cached_property(device, "Address"); - gsize address_len; - const gchar *address_str = g_variant_get_string(address_v, &address_len); - GVariant *alias_v = g_dbus_proxy_get_cached_property(device, "Alias"); - const gchar *alias_str = g_variant_get_string(alias_v, NULL); - if (g_ascii_strcasecmp(address_str, name_str) == 0 || g_strcmp0(alias_str, name_str) == 0) { - match = mp_obj_new_str(address_str, address_len); - } - - g_variant_unref(alias_v); - g_variant_unref(address_v); - g_object_unref(device); - - if (match != mp_const_none) { - break; - } - } - g_list_free_full(objects, g_object_unref); - g_object_unref(object_manager); - - return match; -} -static MP_DEFINE_CONST_FUN_OBJ_1(ev3dev_bluetooth_resolve_obj, ev3dev_bluetooth_resolve); - -static const mp_rom_map_elem_t ev3dev_bluetooth_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bluetooth_c) }, - { MP_ROM_QSTR(MP_QSTR_resolve), MP_ROM_PTR(&ev3dev_bluetooth_resolve_obj) }, -}; -static MP_DEFINE_CONST_DICT(ev3dev_bluetooth_globals, ev3dev_bluetooth_globals_table); - -const mp_obj_module_t pb_module_bluetooth = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&ev3dev_bluetooth_globals, -}; - -MP_REGISTER_MODULE(MP_QSTR_bluetooth_c, pb_module_bluetooth); diff --git a/bricks/ev3dev/modmedia_ev3dev.c b/bricks/ev3dev/modmedia_ev3dev.c deleted file mode 100644 index eff1ff8f6..000000000 --- a/bricks/ev3dev/modmedia_ev3dev.c +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2019-2020 The Pybricks Authors - -#include "py/mpconfig.h" - -#if PYBRICKS_PY_MEDIA_EV3DEV - -#include "py/obj.h" - -#include "pb_ev3dev_types.h" - -#if !MICROPY_MODULE_BUILTIN_INIT -#error "media.ev3dev module requires that MICROPY_MODULE_BUILTIN_INIT is enabled" -#endif - -static mp_obj_t media_ev3dev___init__(void) { - pb_type_ev3dev_Font_init(); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_0(media_ev3dev___init___obj, media_ev3dev___init__); - -static const mp_rom_map_elem_t media_ev3dev_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_media_ev3dev) }, - { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&media_ev3dev___init___obj) }, - { MP_ROM_QSTR(MP_QSTR_Font), MP_ROM_PTR(&pb_type_ev3dev_Font) }, - { MP_ROM_QSTR(MP_QSTR_Image), MP_ROM_PTR(&pb_type_ev3dev_Image) }, -}; -static MP_DEFINE_CONST_DICT(pb_module_media_ev3dev_globals, media_ev3dev_globals_table); - -const mp_obj_module_t pb_module_media_ev3dev = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&pb_module_media_ev3dev_globals, -}; - -MP_REGISTER_MODULE(MP_QSTR_media_ev3dev_c, pb_module_media_ev3dev); - -#endif // PYBRICKS_PY_MEDIA_EV3DEV diff --git a/bricks/ev3dev/modules/core.py b/bricks/ev3dev/modules/core.py deleted file mode 100644 index f2cb4b5d5..000000000 --- a/bricks/ev3dev/modules/core.py +++ /dev/null @@ -1,17 +0,0 @@ -"""Conveniently import core functionality for use on the REPL.""" -from pybricks.hubs import EV3Brick -from pybricks.ev3devices import ( - Motor, - TouchSensor, - ColorSensor, - InfraredSensor, - UltrasonicSensor, - GyroSensor, -) -from pybricks.parameters import Port, Stop, Direction, Button, Color -from pybricks.tools import read_input_byte, wait, StopWatch, DataLog -from pybricks.robotics import DriveBase -from pybricks.media.ev3dev import ImageFile, SoundFile - -# Create an instance of the EV3 Brick -ev3 = EV3Brick() diff --git a/bricks/ev3dev/modules/pybricks/__init__.py b/bricks/ev3dev/modules/pybricks/__init__.py deleted file mode 100644 index 14bf003c4..000000000 --- a/bricks/ev3dev/modules/pybricks/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: MIT -# Copyright (c) 2018-2020 The Pybricks Authors - -from pybricks_c import version diff --git a/bricks/ev3dev/modules/pybricks/bluetooth.py b/bricks/ev3dev/modules/pybricks/bluetooth.py deleted file mode 100644 index 221d817fc..000000000 --- a/bricks/ev3dev/modules/pybricks/bluetooth.py +++ /dev/null @@ -1,188 +0,0 @@ -# SPDX-License-Identifier: MIT -# Copyright (c) 2020 The Pybricks Authors - -""" -:class:`RFCOMMServer` can be used to communicate with other Bluetooth RFCOMM -devices that don't support the EV3 mailbox protocol. - -It is based on the standard library ``socketserver`` module and attempts to -remain a strict subset of that implementation when it comes to low-level -implementation details. -""" - -from _thread import start_new_thread -from uctypes import addressof, sizeof, struct, ARRAY, UINT8, UINT16 -from usocket import socket, SOCK_STREAM - -from bluetooth_c import resolve - -# stuff from bluetooth/bluetooth.h - -AF_BLUETOOTH = 31 -BTPROTO_RFCOMM = 3 -BDADDR_ANY = "00:00:00:00:00:00" - -sa_family_t = UINT16 - -bd_addr_t = {"b": (ARRAY | 0, UINT8 | 6)} - -sockaddr_rc = { - "rc_family": sa_family_t | 0, - "rc_bdaddr": (2, bd_addr_t), - "rc_channel": UINT8 | 8, -} - - -def str2ba(string, ba): - """Convert string to Bluetooth address""" - for i, v in enumerate(string.split(":")): - ba.b[5 - i] = int(v, 16) - - -def ba2str(ba): - """Convert Bluetooth address to string""" - string = [] - for b in ba.b: - string.append("{:02X}".format(b)) - string.reverse() - return ":".join(string).upper() - - -class RFCOMMServer: - """Object that simplifies setting up an RFCOMM socket server. - - This is based on the ``socketserver.SocketServer`` class in the Python - standard library. - """ - - request_queue_size = 1 - - def __init__(self, server_address, RequestHandlerClass): - self.server_address = server_address - self.RequestHandlerClass = RequestHandlerClass - - self.socket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM) - - try: - addr_data = bytearray(sizeof(sockaddr_rc)) - addr = struct(addressof(addr_data), sockaddr_rc) - addr.rc_family = AF_BLUETOOTH - str2ba(server_address[0], addr.rc_bdaddr) - addr.rc_channel = server_address[1] - self.socket.bind(addr_data) - # self.server_address = self.socket.getsockname() - self.socket.listen(self.request_queue_size) - except: - self.server_close() - raise - - def __enter__(self): - return self - - def __exit__(self, type, value, traceback): - self.server_close() - - def handle_request(self): - try: - request, addr_data = self.socket.accept() - except OSError: - return - - try: - addr = struct(addressof(addr_data), sockaddr_rc) - client_address = (ba2str(addr.rc_bdaddr), addr.rc_channel) - self.process_request(request, client_address) - except: - request.close() - raise - - def process_request(self, request, client_address): - self.finish_request(request, client_address) - request.close() - - def finish_request(self, request, client_address): - self.RequestHandlerClass(request, client_address, self) - - def server_close(self): - self.socket.close() - - -class ThreadingMixIn: - def process_request_thread(self, request, client_address): - try: - self.finish_request(request, client_address) - finally: - request.close() - - def process_request(self, request, client_address): - start_new_thread(self.process_request_thread, (request, client_address)) - - -class ThreadingRFCOMMServer(ThreadingMixIn, RFCOMMServer): - """Version of :class:`RFCOMMServer` that handles connections in a new - thread. - """ - - pass - - -class StreamRequestHandler: - """Class that handles incoming requests. - - This is based on ``socketserver.StreamRequestHandler`` from the Python - standard library. - """ - - def __init__(self, request, client_address, server): - self.request = request - self.client_address = client_address - self.server = server - self.setup() - try: - self.handle() - finally: - self.finish() - - def setup(self): - self.wfile = self.request - self.rfile = self.request - - def handle(self): - pass - - def finish(self): - pass - - -class RFCOMMClient: - def __init__(self, client_address, RequestHandlerClass): - self.client_address = client_address - self.RequestHandlerClass = RequestHandlerClass - self.socket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM) - - def handle_request(self): - addr_data = bytearray(sizeof(sockaddr_rc)) - addr = struct(addressof(addr_data), sockaddr_rc) - addr.rc_family = AF_BLUETOOTH - str2ba(self.client_address[0], addr.rc_bdaddr) - addr.rc_channel = self.client_address[1] - self.socket.connect(addr_data) - try: - self.process_request(self.socket, self.client_address) - except: - self.socket.close() - raise - - def process_request(self, request, client_address): - self.finish_request(request, client_address) - request.close() - - def finish_request(self, request, client_address): - self.RequestHandlerClass(request, client_address, self) - - def client_close(self): - self.socket.close() - - -class ThreadingRFCOMMClient(ThreadingMixIn, RFCOMMClient): - pass diff --git a/bricks/ev3dev/modules/pybricks/experimental.py b/bricks/ev3dev/modules/pybricks/experimental.py deleted file mode 100644 index 8f22b44ee..000000000 --- a/bricks/ev3dev/modules/pybricks/experimental.py +++ /dev/null @@ -1,88 +0,0 @@ -"""The experimental module contains unstable APIs for development and testing. -""" - -from _experimental import pthread_raise -from _thread import start_new_thread, get_ident, allocate_lock -from usignal import pthread_kill, SIGUSR2 - - -def run_parallel(*args): - """Runs functions in parallel and waits for all to complete. - - If any function has an unhandled exception, all other functions will be - stopped (by raising the ``SystemExit`` exception). - - Arguments: - * (callable): - Two or more functions with no required parameters. - - Returns: - A dictionary mapping the functions to their return value (or a - ``SystemExit`` exception object if the function was interrupted). - - Raises: - TypeError: - Fewer than 2 arguments or one of the arguments is not callable. - RuntimeError: - Any of the functions had an unhandled exception. The argument at - index 1 will be a dictionary mapping the functions to the - exceptions (or result if a function finished before the unhandled - exception in another function). - - Example:: - - from pybricks.experimental import run_parallel - from pybricks.tools import wait - - def task1(): - wait(1000) - return 'OK1' - - def task2(): - wait(500) - return 'OK2' - - result = run_parallel(task1, task2) - print('task1:', repr(result[task1])) - print('task2:', repr(result[task2])) - - # prints: - # task1: 'OK1' - # task2: 'OK2' - """ - if len(args) < 2: - raise TypeError("requires at least 2 arguments") - for n, arg in enumerate(args): - if not callable(arg): - raise TypeError("argument {} is not callable".format(n)) - - ids = set() - lock = allocate_lock() - lock.acquire() - results = {} - unhandled_ex = False - - def wrapper(func): - nonlocal unhandled_ex - try: - results[func] = func() - except BaseException as ex: - results[func] = ex - if isinstance(ex, Exception): - unhandled_ex = True - finally: - ids.remove(get_ident()) - if not ids: - lock.release() - elif unhandled_ex: - id = next(iter(ids)) - pthread_raise(id, SystemExit()) - pthread_kill(id, SIGUSR2) - - for arg in args: - ids.add(start_new_thread(wrapper, (arg,))) - - lock.acquire() - if any(isinstance(x, Exception) for x in results.values()): - raise RuntimeError("An unhandled exception occurred in run_parallel", results) - return results diff --git a/bricks/ev3dev/modules/pybricks/media/ev3dev.py b/bricks/ev3dev/modules/pybricks/media/ev3dev.py deleted file mode 100644 index 8901abec6..000000000 --- a/bricks/ev3dev/modules/pybricks/media/ev3dev.py +++ /dev/null @@ -1,172 +0,0 @@ -from media_ev3dev_c import Font, Image - - -class SoundFile: - _BASE_PATH = "/usr/share/sounds/ev3dev/" - - CAT_PURR = _BASE_PATH + "animals/cat_purr.wav" - DOG_BARK_1 = _BASE_PATH + "animals/dog_bark_1.wav" - DOG_BARK_2 = _BASE_PATH + "animals/dog_bark_2.wav" - DOG_GROWL = _BASE_PATH + "animals/dog_growl.wav" - DOG_SNIFF = _BASE_PATH + "animals/dog_sniff.wav" - DOG_WHINE = _BASE_PATH + "animals/dog_whine.wav" - ELEPHANT_CALL = _BASE_PATH + "animals/elephant_call.wav" - INSECT_BUZZ_1 = _BASE_PATH + "animals/insect_buzz_1.wav" - INSECT_BUZZ_2 = _BASE_PATH + "animals/insect_buzz_2.wav" - INSECT_CHIRP = _BASE_PATH + "animals/insect_chirp.wav" - SNAKE_HISS = _BASE_PATH + "animals/snake_hiss.wav" - SNAKE_RATTLE = _BASE_PATH + "animals/snake_rattle.wav" - T_REX_ROAR = _BASE_PATH + "animals/t-rex_roar.wav" - - BLACK = _BASE_PATH + "colors/black.wav" - BLUE = _BASE_PATH + "colors/blue.wav" - BROWN = _BASE_PATH + "colors/brown.wav" - GREEN = _BASE_PATH + "colors/green.wav" - RED = _BASE_PATH + "colors/red.wav" - WHITE = _BASE_PATH + "colors/white.wav" - YELLOW = _BASE_PATH + "colors/yellow.wav" - - BRAVO = _BASE_PATH + "communication/bravo.wav" - EV3 = _BASE_PATH + "communication/ev3.wav" - FANTASTIC = _BASE_PATH + "communication/fantastic.wav" - GAME_OVER = _BASE_PATH + "communication/game_over.wav" - GO = _BASE_PATH + "communication/go.wav" - GOOD = _BASE_PATH + "communication/good.wav" - GOOD_JOB = _BASE_PATH + "communication/good_job.wav" - GOODBYE = _BASE_PATH + "communication/goodbye.wav" - HELLO = _BASE_PATH + "communication/hello.wav" - HI = _BASE_PATH + "communication/hi.wav" - LEGO = _BASE_PATH + "communication/lego.wav" - MINDSTORMS = _BASE_PATH + "communication/mindstorms.wav" - MORNING = _BASE_PATH + "communication/morning.wav" - NO = _BASE_PATH + "communication/no.wav" - OKAY = _BASE_PATH + "communication/okay.wav" - OKEY_DOKEY = _BASE_PATH + "communication/okey-dokey.wav" - SORRY = _BASE_PATH + "communication/sorry.wav" - THANK_YOU = _BASE_PATH + "communication/thank_you.wav" - YES = _BASE_PATH + "communication/yes.wav" - - BOING = _BASE_PATH + "expressions/boing.wav" - BOO = _BASE_PATH + "expressions/boo.wav" - CHEERING = _BASE_PATH + "expressions/cheering.wav" - CRUNCHING = _BASE_PATH + "expressions/crunching.wav" - CRYING = _BASE_PATH + "expressions/crying.wav" - FANFARE = _BASE_PATH + "expressions/fanfare.wav" - KUNG_FU = _BASE_PATH + "expressions/kung_fu.wav" - LAUGHING_1 = _BASE_PATH + "expressions/laughing_1.wav" - LAUGHING_2 = _BASE_PATH + "expressions/laughing_2.wav" - MAGIC_WAND = _BASE_PATH + "expressions/magic_wand.wav" - OUCH = _BASE_PATH + "expressions/ouch.wav" - SHOUTING = _BASE_PATH + "expressions/shouting.wav" - SMACK = _BASE_PATH + "expressions/smack.wav" - SNEEZING = _BASE_PATH + "expressions/sneezing.wav" - SNORING = _BASE_PATH + "expressions/snoring.wav" - UH_OH = _BASE_PATH + "expressions/uh-oh.wav" - - ACTIVATE = _BASE_PATH + "information/activate.wav" - ANALYZE = _BASE_PATH + "information/analyze.wav" - BACKWARDS = _BASE_PATH + "information/backwards.wav" - COLOR = _BASE_PATH + "information/color.wav" - DETECTED = _BASE_PATH + "information/detected.wav" - DOWN = _BASE_PATH + "information/down.wav" - ERROR = _BASE_PATH + "information/error.wav" - ERROR_ALARM = _BASE_PATH + "information/error_alarm.wav" - FLASHING = _BASE_PATH + "information/flashing.wav" - FORWARD = _BASE_PATH + "information/forward.wav" - LEFT = _BASE_PATH + "information/left.wav" - OBJECT = _BASE_PATH + "information/object.wav" - RIGHT = _BASE_PATH + "information/right.wav" - SEARCHING = _BASE_PATH + "information/searching.wav" - START = _BASE_PATH + "information/start.wav" - STOP = _BASE_PATH + "information/stop.wav" - TOUCH = _BASE_PATH + "information/touch.wav" - TURN = _BASE_PATH + "information/turn.wav" - UP = _BASE_PATH + "information/up.wav" - - AIR_RELEASE = _BASE_PATH + "mechanical/air_release.wav" - AIRBRAKE = _BASE_PATH + "mechanical/airbrake.wav" - BACKING_ALERT = _BASE_PATH + "mechanical/backing_alert.wav" - HORN_1 = _BASE_PATH + "mechanical/horn_1.wav" - HORN_2 = _BASE_PATH + "mechanical/horn_2.wav" - LASER = _BASE_PATH + "mechanical/laser.wav" - MOTOR_IDLE = _BASE_PATH + "mechanical/motor_idle.wav" - MOTOR_START = _BASE_PATH + "mechanical/motor_start.wav" - MOTOR_STOP = _BASE_PATH + "mechanical/motor_stop.wav" - RATCHET = _BASE_PATH + "mechanical/ratchet.wav" - SONAR = _BASE_PATH + "mechanical/sonar.wav" - TICK_TACK = _BASE_PATH + "mechanical/tick_tack.wav" - - SPEED_DOWN = _BASE_PATH + "movements/speed_down.wav" - SPEED_IDLE = _BASE_PATH + "movements/speed_idle.wav" - SPEED_UP = _BASE_PATH + "movements/speed_up.wav" - - ZERO = _BASE_PATH + "numbers/zero.wav" - ONE = _BASE_PATH + "numbers/one.wav" - TWO = _BASE_PATH + "numbers/two.wav" - THREE = _BASE_PATH + "numbers/three.wav" - FOUR = _BASE_PATH + "numbers/four.wav" - FIVE = _BASE_PATH + "numbers/five.wav" - SIX = _BASE_PATH + "numbers/six.wav" - SEVEN = _BASE_PATH + "numbers/seven.wav" - EIGHT = _BASE_PATH + "numbers/eight.wav" - NINE = _BASE_PATH + "numbers/nine.wav" - TEN = _BASE_PATH + "numbers/ten.wav" - - CLICK = _BASE_PATH + "system/click.wav" - CONFIRM = _BASE_PATH + "system/confirm.wav" - GENERAL_ALERT = _BASE_PATH + "system/general_alert.wav" - OVERPOWER = _BASE_PATH + "system/overpower.wav" - READY = _BASE_PATH + "system/ready.wav" - - -class ImageFile: - _BASE_PATH = "/usr/share/images/ev3dev/mono/" - - ANGRY = _BASE_PATH + "eyes/angry.png" - AWAKE = _BASE_PATH + "eyes/awake.png" - BLACK_EYE = _BASE_PATH + "eyes/black_eye.png" - BOTTOM_LEFT = _BASE_PATH + "eyes/bottom_left.png" - BOTTOM_RIGHT = _BASE_PATH + "eyes/bottom_right.png" - CRAZY_1 = _BASE_PATH + "eyes/crazy_1.png" - CRAZY_2 = _BASE_PATH + "eyes/crazy_2.png" - DISAPPOINTED = _BASE_PATH + "eyes/disappointed.png" - DIZZY = _BASE_PATH + "eyes/dizzy.png" - DOWN = _BASE_PATH + "eyes/down.png" - EVIL = _BASE_PATH + "eyes/evil.png" - HURT = _BASE_PATH + "eyes/hurt.png" - KNOCKED_OUT = _BASE_PATH + "eyes/knocked_out.png" - LOVE = _BASE_PATH + "eyes/love.png" - MIDDLE_LEFT = _BASE_PATH + "eyes/middle_left.png" - MIDDLE_RIGHT = _BASE_PATH + "eyes/middle_right.png" - NEUTRAL = _BASE_PATH + "eyes/neutral.png" - NUCLEAR = _BASE_PATH + "eyes/nuclear.png" - PINCHED_LEFT = _BASE_PATH + "eyes/pinched_left.png" - PINCHED_MIDDLE = _BASE_PATH + "eyes/pinched_middle.png" - PINCHED_RIGHT = _BASE_PATH + "eyes/pinched_right.png" - SLEEPING = _BASE_PATH + "eyes/sleeping.png" - TEAR = _BASE_PATH + "eyes/tear.png" - TIRED_LEFT = _BASE_PATH + "eyes/tired_left.png" - TIRED_MIDDLE = _BASE_PATH + "eyes/tired_middle.png" - TIRED_RIGHT = _BASE_PATH + "eyes/tired_right.png" - TOXIC = _BASE_PATH + "eyes/toxic.png" - UP = _BASE_PATH + "eyes/up.png" - WINKING = _BASE_PATH + "eyes/winking.png" - - ACCEPT = _BASE_PATH + "information/accept.png" - BACKWARD = _BASE_PATH + "information/backward.png" - DECLINE = _BASE_PATH + "information/decline.png" - FORWARD = _BASE_PATH + "information/forward.png" - LEFT = _BASE_PATH + "information/left.png" - NO_GO = _BASE_PATH + "information/no_go.png" - QUESTION_MARK = _BASE_PATH + "information/question_mark.png" - RIGHT = _BASE_PATH + "information/right.png" - STOP_1 = _BASE_PATH + "information/stop_1.png" - STOP_2 = _BASE_PATH + "information/stop_2.png" - THUMBS_DOWN = _BASE_PATH + "information/thumbs_down.png" - THUMBS_UP = _BASE_PATH + "information/thumbs_up.png" - WARNING = _BASE_PATH + "information/warning.png" - - EV3 = _BASE_PATH + "lego/ev3.png" - EV3_ICON = _BASE_PATH + "lego/ev3_icon.png" - - TARGET = _BASE_PATH + "objects/target.png" diff --git a/bricks/ev3dev/modules/pybricks/messaging.py b/bricks/ev3dev/modules/pybricks/messaging.py deleted file mode 100644 index f0a099534..000000000 --- a/bricks/ev3dev/modules/pybricks/messaging.py +++ /dev/null @@ -1,342 +0,0 @@ -# SPDX-License-Identifier: MIT -# Copyright (c) 2020 The Pybricks Authors - -from _thread import allocate_lock -from uerrno import ECONNRESET -from ustruct import pack, unpack - -from pybricks.bluetooth import ( - resolve, - BDADDR_ANY, - ThreadingRFCOMMServer, - ThreadingRFCOMMClient, - StreamRequestHandler, -) - - -class Mailbox: - def __init__(self, name, connection, encode=None, decode=None): - """Object that represents a mailbox for sending an receiving messages - from other connected devices. - - Arguments: - name (str): - The name of this mailbox. - connection: - A connection object that implements the mailbox connection - interface. - encode: - A function that encodes an object into a bytes-like object. - decode: - A function that decodes an object from a bytes-like object. - """ - self.name = name - self._connection = connection - - if encode: - self.encode = encode - - if decode: - self.decode = decode - - def encode(self, value): - return value - - def decode(self, payload): - return payload - - def read(self): - """Reads the current value of the mailbox. - - Returns: - The decoded value or ``None`` if the mailbox has never received - a value. - """ - data = self._connection.read_from_mailbox(self.name) - if data is None: - return None - return self.decode(data) - - def send(self, value, destination=None): - """Sends a value to remote mailboxes with the same name as this - mailbox. - - Arguments: - value: The value to send. - destination: The name or address of a specific device or ``None`` - to broadcast to all connected devices. - """ - data = self.encode(value) - self._connection.send_to_mailbox(destination, self.name, data) - - def wait(self): - """Waits for the mailbox to receive a message.""" - self._connection.wait_for_mailbox_update(self.name) - - def wait_new(self): - """Waits for the mailbox to receive a message that is different from - the current contents of the mailbox. - - Returns: - The new value. (Same as return value of :meth:`read`.) - """ - old = self.read() - while True: - self.wait() - new = self.read() - if new != old: - return new - - -class LogicMailbox(Mailbox): - """:class:`Mailbox` that holds a logic or boolean value. - - This is compatible with the "logic" message blocks in the standard - EV3 firmware. - """ - - def encode(self, value): - return b"\x01" if value else b"\x00" - - def decode(self, payload): - return bool(payload[0]) - - -class NumericMailbox(Mailbox): - """:class:`Mailbox` that holds a numeric or floating point value. - - This is compatible with the "numeric" message blocks in the standard - EV3 firmware. - """ - - def encode(self, value): - return pack(" 0 and length == 0: - print(*headers, sep=", ", file=self.file) - - def log(self, *values): - print(*values, sep=", ", file=self.file) - - def __repr__(self): - self.file.seek(0, 0) - return self.file.read() diff --git a/bricks/ev3dev/modusignal.c b/bricks/ev3dev/modusignal.c deleted file mode 100644 index bb7b45a5b..000000000 --- a/bricks/ev3dev/modusignal.c +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2020 The Pybricks Authors - -// This is a subset of the standard CPython signal module. - -#include "py/mpconfig.h" - -#if PYBRICKS_PY_USIGNAL - -#include -#include - -#include "py/mpthread.h" -#include "py/obj.h" -#include "py/runtime.h" - -static mp_obj_t usignal_pause(void) { - - MP_THREAD_GIL_EXIT(); - pause(); - MP_THREAD_GIL_ENTER(); - mp_handle_pending(true); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_0(usignal_pause_obj, usignal_pause); - -#if MICROPY_PY_THREAD -static mp_obj_t usignal_pthread_kill(mp_obj_t thread_id_in, mp_obj_t signalnum_in) { - - mp_int_t thread_id = mp_obj_int_get_truncated(thread_id_in); - mp_int_t signalnum = mp_obj_get_int(signalnum_in); - int err = pthread_kill(thread_id, signalnum); - if (err) { - mp_raise_OSError(err); - } - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(usignal_pthread_kill_obj, usignal_pthread_kill); -#endif // MICROPY_PY_THREAD - -static const mp_rom_map_elem_t usignal_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usignal) }, - { MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&usignal_pause_obj) }, - #if MICROPY_PY_THREAD - { MP_ROM_QSTR(MP_QSTR_pthread_kill), MP_ROM_PTR(&usignal_pthread_kill_obj) }, - #endif // MICROPY_PY_THREAD - { MP_ROM_QSTR(MP_QSTR_SIGHUP), MP_ROM_INT(SIGHUP) }, - { MP_ROM_QSTR(MP_QSTR_SIGINT), MP_ROM_INT(SIGINT) }, - { MP_ROM_QSTR(MP_QSTR_SIGTERM), MP_ROM_INT(SIGTERM) }, - { MP_ROM_QSTR(MP_QSTR_SIGUSR1), MP_ROM_INT(SIGUSR1) }, - { MP_ROM_QSTR(MP_QSTR_SIGUSR2), MP_ROM_INT(SIGUSR2) }, -}; -static MP_DEFINE_CONST_DICT(pb_module_usignal_globals, usignal_globals_table); - -const mp_obj_module_t pb_module_usignal = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&pb_module_usignal_globals, -}; - -MP_REGISTER_MODULE(MP_QSTR_usignal, pb_module_usignal); - -#endif // PYBRICKS_PY_USIGNAL diff --git a/bricks/ev3dev/mpconfigport.h b/bricks/ev3dev/mpconfigport.h deleted file mode 100644 index 557fb5c85..000000000 --- a/bricks/ev3dev/mpconfigport.h +++ /dev/null @@ -1,420 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2013, 2014 Damien P. George -// Copyright (c) 2018-2023 The Pybricks Authors - -// Pybricks brick specific definitions -#include "brickconfig.h" - -static const char pybricks_ev3dev_help_text[] = - "Welcome to Pybricks MicroPython!\n" - "\n" - "For online docs please visit http://docs.pybricks.com/micropython\n" - "\n" - "Control commands:\n" - " CTRL-C -- interrupt a running program\n" - " CTRL-D -- on a blank line, exit\n" - " CTRL-E -- on a blank line, enter paste mode\n" - "\n" - "For further help on a specific object, type help(obj)\n" -; - -// options to control how MicroPython is built - -#define MICROPY_BANNER_NAME_AND_VERSION "Pybricks MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE - -#define MICROPY_ALLOC_PATH_MAX (PATH_MAX) -#define MICROPY_PERSISTENT_CODE_LOAD (1) -#if !defined(MICROPY_EMIT_X64) && defined(__x86_64__) - #define MICROPY_EMIT_X64 (1) -#endif -#if !defined(MICROPY_EMIT_X86) && defined(__i386__) - #define MICROPY_EMIT_X86 (1) -#endif -#if !defined(MICROPY_EMIT_THUMB) && defined(__thumb2__) - #define MICROPY_EMIT_THUMB (1) - #define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p) | 1)) -#endif -// Some compilers define __thumb2__ and __arm__ at the same time, let -// autodetected thumb2 emitter have priority. -#if !defined(MICROPY_EMIT_ARM) && defined(__arm__) && !defined(__thumb2__) - #define MICROPY_EMIT_ARM (1) -#endif -#define MICROPY_COMP_MODULE_CONST (1) -#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1) -#define MICROPY_COMP_RETURN_IF_EXPR (1) -#define MICROPY_ENABLE_GC (1) -#define MICROPY_ENABLE_FINALISER (1) -#define MICROPY_STACK_CHECK (1) -#define MICROPY_MALLOC_USES_ALLOCATED_SIZE (1) -#define MICROPY_MEM_STATS (1) -#define MICROPY_DEBUG_PRINTERS (1) -// Printing debug to stderr may give tests which -// check stdout a chance to pass, etc. -#define MICROPY_DEBUG_PRINTER (&mp_stderr_print) -#define MICROPY_READER_POSIX (1) -#define MICROPY_READER_VFS (1) -#define MICROPY_USE_READLINE_HISTORY (1) -#define MICROPY_HELPER_REPL (1) -#define MICROPY_REPL_EMACS_KEYS (1) -#define MICROPY_REPL_AUTO_INDENT (1) -#define MICROPY_HELPER_LEXER_UNIX (1) -#define MICROPY_ENABLE_SOURCE_LINE (1) -#define MICROPY_ENABLE_DOC_STRING (1) -#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE) -#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) -#define MICROPY_STREAMS_NON_BLOCK (1) -#define MICROPY_STREAMS_POSIX_API (1) -#define MICROPY_OPT_COMPUTED_GOTO (1) -#define MICROPY_MODULE_OVERRIDE_MAIN_IMPORT (1) -#define MICROPY_VFS (1) -#define MICROPY_VFS_POSIX (1) -#define MICROPY_PY_SYS_PATH_ARGV_DEFAULTS (0) -#ifndef MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE -#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (1) -#endif -#define MICROPY_MODULE_WEAK_LINKS (1) -#define MICROPY_CAN_OVERRIDE_BUILTINS (1) -#define MICROPY_PY_FUNCTION_ATTRS (1) -#define MICROPY_PY_DESCRIPTORS (1) -#define MICROPY_PY_BUILTINS_STR_UNICODE (1) -#define MICROPY_PY_BUILTINS_STR_CENTER (1) -#define MICROPY_PY_BUILTINS_STR_PARTITION (1) -#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1) -#define MICROPY_PY_BUILTINS_MEMORYVIEW (1) -#define MICROPY_PY_BUILTINS_FROZENSET (1) -#define MICROPY_PY_BUILTINS_COMPILE (1) -#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1) -#define MICROPY_PY_BUILTINS_INPUT (1) -#define MICROPY_PY_BUILTINS_HELP (1) -#define MICROPY_PY_BUILTINS_HELP_TEXT pybricks_ev3dev_help_text -#define MICROPY_PY_BUILTINS_HELP_MODULES (1) -#define MICROPY_PY_BUILTINS_POW3 (1) -#define MICROPY_PY_BUILTINS_ROUND_INT (1) -#define MICROPY_PY_MICROPYTHON_MEM_INFO (1) -#define MICROPY_PY_ALL_SPECIAL_METHODS (1) -#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) -#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) -#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) -#define MICROPY_PY_BUILTINS_SLICE_INDICES (1) -#define MICROPY_PY_INSTANCE_ATTRS (1) -#define MICROPY_PY_SYS_EXIT (1) -#define MICROPY_PY_SYS_ATEXIT (1) -#if MICROPY_PY_SYS_SETTRACE -#define MICROPY_PERSISTENT_CODE_SAVE (1) -#define MICROPY_COMP_CONST (0) -#endif -#ifndef MICROPY_PY_SYS_PLATFORM -#if defined(__APPLE__) && defined(__MACH__) - #define MICROPY_PY_SYS_PLATFORM "darwin" -#else - #define MICROPY_PY_SYS_PLATFORM "linux" -#endif -#endif -#ifndef MICROPY_PY_SYS_PATH_DEFAULT -#define MICROPY_PY_SYS_PATH_DEFAULT ".frozen:~/.pybricks-micropython/lib" -#endif -#define MICROPY_PY_SYS_MAXSIZE (1) -#define MICROPY_PY_SYS_STDFILES (1) -#define MICROPY_PY_SYS_EXC_INFO (0) -#define MICROPY_PY_COLLECTIONS_DEQUE (1) -#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) -#ifndef MICROPY_PY_MATH_SPECIAL_FUNCTIONS -#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) -#endif -#define MICROPY_PY_CMATH (1) -#define MICROPY_PY_IO_IOBASE (1) -#define MICROPY_PY_IO_FILEIO (1) -#define MICROPY_PY_GC_COLLECT_RETVAL (1) -#define MICROPY_MODULE_ATTR_DELEGATION (1) -#define MICROPY_MODULE_BUILTIN_INIT (1) - -#define MICROPY_PY_THREAD (1) -#define MICROPY_PY_THREAD_GIL (1) - -#ifndef MICROPY_STACKLESS -#define MICROPY_STACKLESS (0) -#define MICROPY_STACKLESS_STRICT (0) -#endif - -#define MICROPY_OPT_MATH_FACTORIAL (0) -#define MICROPY_FLOAT_HIGH_QUALITY_HASH (1) -#define MICROPY_ENABLE_SCHEDULER (0) -#define MICROPY_WARNINGS_CATEGORY (1) -#define MICROPY_MODULE_GETATTR (1) -#define MICROPY_PY_DELATTR_SETATTR (1) -#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) -#define MICROPY_PY_BUILTINS_BYTES_HEX (1) -#define MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE (1) -#define MICROPY_PY_BUILTINS_NEXT2 (1) -#define MICROPY_PY_BUILTINS_RANGE_BINOP (1) -#define MICROPY_PY_SYS_GETSIZEOF (1) -#define MICROPY_PY_MATH_FACTORIAL (1) -#define MICROPY_PY_IO_BUFFEREDWRITER (1) -#define MICROPY_PY_IO_RESOURCE_STREAM (1) -#define MICROPY_PY_URE_MATCH_GROUPS (1) -#define MICROPY_PY_URE_MATCH_SPAN_START_END (1) -#define MICROPY_PY_URE_SUB (1) -#define MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT (1) - -#define MICROPY_PY_FRAMEBUF (1) -#define MICROPY_PY_UOS (1) -#define MICROPY_PY_UOS_INCLUDEFILE "ports/unix/moduos.c" -#define MICROPY_PY_UOS_ERRNO (1) -#define MICROPY_PY_UOS_GETENV_PUTENV_UNSETENV (1) -#define MICROPY_PY_UOS_SEP (1) -#define MICROPY_PY_UOS_STATVFS (0) -#define MICROPY_PY_UOS_SYSTEM (1) -#define MICROPY_PY_UOS_URANDOM (1) -#define MICROPY_PY_UTIME (1) -#define MICROPY_PY_UTIME_MP_HAL (1) -#define MICROPY_PY_UERRNO (1) -#define MICROPY_PY_UERRNO_LIST \ - X(EPERM) \ - X(ENOENT) \ - X(ESRCH) \ - X(EINTR) \ - X(EIO) \ - X(ENXIO) \ - X(E2BIG) \ - X(ENOEXEC) \ - X(EBADF) \ - X(ECHILD) \ - X(EAGAIN) \ - X(ENOMEM) \ - X(EACCES) \ - X(EFAULT) \ - X(ENOTBLK) \ - X(EBUSY) \ - X(EEXIST) \ - X(EXDEV) \ - X(ENODEV) \ - X(ENOTDIR) \ - X(EISDIR) \ - X(EINVAL) \ - X(ENFILE) \ - X(EMFILE) \ - X(ENOTTY) \ - X(ETXTBSY) \ - X(EFBIG) \ - X(ENOSPC) \ - X(ESPIPE) \ - X(EROFS) \ - X(EMLINK) \ - X(EPIPE) \ - X(EDOM) \ - X(ERANGE) \ - X(EOPNOTSUPP) \ - X(EAFNOSUPPORT) \ - X(EADDRINUSE) \ - X(ECONNABORTED) \ - X(ECONNRESET) \ - X(ENOBUFS) \ - X(EISCONN) \ - X(ENOTCONN) \ - X(ETIMEDOUT) \ - X(ECONNREFUSED) \ - X(EHOSTUNREACH) \ - X(EALREADY) \ - X(EINPROGRESS) \ - X(ECANCELED) \ - -#define MICROPY_PY_UCTYPES (1) -#define MICROPY_PY_UZLIB (1) -#define MICROPY_PY_UJSON (1) -#define MICROPY_PY_URE (1) -#define MICROPY_PY_UHEAPQ (1) -#define MICROPY_PY_UTIMEQ (1) -#define MICROPY_PY_USOCKET_LISTEN_BACKLOG_DEFAULT (SOMAXCONN < 128 ? SOMAXCONN : 128) -#define MICROPY_PY_UHASHLIB (1) -#if MICROPY_PY_USSL -#define MICROPY_PY_UHASHLIB_MD5 (1) -#define MICROPY_PY_UHASHLIB_SHA1 (1) -#define MICROPY_PY_UCRYPTOLIB (1) -#endif -#define MICROPY_PY_UBINASCII (1) -#define MICROPY_PY_UBINASCII_CRC32 (1) -#define MICROPY_PY_UFCNTL_POSIX (1) -#define MICROPY_PY_URANDOM (1) -#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) -#define MICROPY_PY_URANDOM_SEED_INIT_FUNC (mp_urandom_seed_init()) -#ifndef MICROPY_PY_USELECT_POSIX -#define MICROPY_PY_USELECT_POSIX (1) -#endif -#define MICROPY_PY_UWEBSOCKET (1) -#define MICROPY_PY_MACHINE (1) -#define MICROPY_PY_MACHINE_PULSE (1) -#define MICROPY_MACHINE_MEM_GET_READ_ADDR mod_machine_mem_get_addr -#define MICROPY_MACHINE_MEM_GET_WRITE_ADDR mod_machine_mem_get_addr - -#define MICROPY_FATFS_ENABLE_LFN (1) -#define MICROPY_FATFS_RPATH (2) -#define MICROPY_FATFS_MAX_SS (4096) -#define MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ - -// Define to MICROPY_ERROR_REPORTING_DETAILED to get function, etc. -// names in exception messages (may require more RAM). -#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED) -#define MICROPY_WARNINGS (1) -#define MICROPY_ERROR_PRINTER (&mp_stderr_print) -#define MICROPY_PY_STR_BYTES_CMP_WARN (1) - -// VFS stat functions should return time values relative to 1970/1/1 -#define MICROPY_EPOCH_IS_1970 (1) - -extern const struct _mp_print_t mp_stderr_print; - -#if !(defined(MICROPY_GCREGS_SETJMP) || defined(__x86_64__) || defined(__i386__) || defined(__thumb2__) || defined(__thumb__) || defined(__arm__)) -// Fall back to setjmp() implementation for discovery of GC pointers in registers. -#define MICROPY_GCREGS_SETJMP (1) -#endif - -#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) -#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (256) -#define MICROPY_KBD_EXCEPTION (1) -#define MICROPY_ASYNC_KBD_INTR (0) - -#define mp_type_fileio mp_type_vfs_posix_fileio -#define mp_type_textio mp_type_vfs_posix_textio - -// type definitions for the specific machine - -// For size_t and ssize_t -#include - -// assume that if we already defined the obj repr then we also defined types -#ifndef MICROPY_OBJ_REPR -#ifdef __LP64__ -typedef long mp_int_t; // must be pointer size -typedef unsigned long mp_uint_t; // must be pointer size -#else -// These are definitions for machines where sizeof(int) == sizeof(void*), -// regardless of actual size. -typedef int mp_int_t; // must be pointer size -typedef unsigned int mp_uint_t; // must be pointer size -#endif -#endif - -// Cannot include , as it may lead to symbol name clashes -#if _FILE_OFFSET_BITS == 64 && !defined(__LP64__) -typedef long long mp_off_t; -#else -typedef long mp_off_t; -#endif - -void mp_unix_alloc_exec(size_t min_size, void **ptr, size_t *size); -void mp_unix_free_exec(void *ptr, size_t size); -void mp_unix_mark_exec(void); -#define MP_PLAT_ALLOC_EXEC(min_size, ptr, size) mp_unix_alloc_exec(min_size, ptr, size) -#define MP_PLAT_FREE_EXEC(ptr, size) mp_unix_free_exec(ptr, size) -#ifndef MICROPY_FORCE_PLAT_ALLOC_EXEC -// Use MP_PLAT_ALLOC_EXEC for any executable memory allocation, including for FFI -// (overriding libffi own implementation) -#define MICROPY_FORCE_PLAT_ALLOC_EXEC (1) -#endif - -#ifdef MICROPY_PY_URANDOM_SEED_INIT_FUNC -// Support for seeding the random module on import. -#include -void mp_hal_get_random(size_t n, void *buf); -static inline unsigned long mp_urandom_seed_init(void) { - unsigned long r; - mp_hal_get_random(sizeof(r), &r); - return r; -} -#endif - -#ifdef __linux__ -// Can access physical memory using /dev/mem -#define MICROPY_PLAT_DEV_MEM (1) -#endif - -// Assume that select() call, interrupted with a signal, and erroring -// with EINTR, updates remaining timeout value. -#define MICROPY_SELECT_REMAINING_TIME (1) - -#ifdef __ANDROID__ -#include -#if __ANDROID_API__ < 4 -// Bionic libc in Android 1.5 misses these 2 functions -#define MP_NEED_LOG2 (1) -#define nan(x) NAN -#endif -#endif - -#define MICROPY_PORT_INIT_FUNC pybricks_init() -#define MICROPY_PORT_DEINIT_FUNC pybricks_deinit() -#define MICROPY_MPHALPORT_H "ev3dev_mphal.h" - -#define MICROPY_PORT_BUILTINS \ - { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, - -#define MP_STATE_PORT MP_STATE_VM - -#if MICROPY_PY_BLUETOOTH -#if MICROPY_BLUETOOTH_BTSTACK -struct _mp_bluetooth_btstack_root_pointers_t; -#define MICROPY_BLUETOOTH_ROOT_POINTERS struct _mp_bluetooth_btstack_root_pointers_t *bluetooth_btstack_root_pointers; -#endif -#if MICROPY_BLUETOOTH_NIMBLE -struct _mp_bluetooth_nimble_root_pointers_t; -struct _mp_bluetooth_nimble_malloc_t; -#define MICROPY_BLUETOOTH_ROOT_POINTERS struct _mp_bluetooth_nimble_malloc_t *bluetooth_nimble_memory; struct _mp_bluetooth_nimble_root_pointers_t *bluetooth_nimble_root_pointers; -#endif -#else -#define MICROPY_BLUETOOTH_ROOT_POINTERS -#endif - -// We need to provide a declaration/definition of alloca() -// unless support for it is disabled. -#if !defined(MICROPY_NO_ALLOCA) || MICROPY_NO_ALLOCA == 0 -#ifdef __FreeBSD__ -#include -#else -#include -#endif -#endif - -// From "man readdir": "Under glibc, programs can check for the availability -// of the fields [in struct dirent] not defined in POSIX.1 by testing whether -// the macros [...], _DIRENT_HAVE_D_TYPE are defined." -// Other libc's don't define it, but proactively assume that dirent->d_type -// is available on a modern *nix system. -#ifndef _DIRENT_HAVE_D_TYPE -#define _DIRENT_HAVE_D_TYPE (1) -#endif -// This macro is not provided by glibc but we need it so ports that don't have -// dirent->d_ino can disable the use of this field. -#ifndef _DIRENT_HAVE_D_INO -#define _DIRENT_HAVE_D_INO (1) -#endif - -#ifndef __APPLE__ -// For debugging purposes, make printf() available to any source file. -#include -#endif - -#if MICROPY_PY_THREAD -#define MICROPY_BEGIN_ATOMIC_SECTION() (mp_thread_unix_begin_atomic_section(), 0xffffffff) -#define MICROPY_END_ATOMIC_SECTION(x) (void)x; mp_thread_unix_end_atomic_section() -#endif - -#define MICROPY_VM_HOOK_LOOP do { \ - extern int pbio_do_one_event(void); \ - pbio_do_one_event(); \ -} while (0); - -#include - -#define MICROPY_EVENT_POLL_HOOK do { \ - extern void mp_handle_pending(bool); \ - mp_handle_pending(true); \ - extern int pbio_do_one_event(void); \ - while (pbio_do_one_event()) { } \ - MP_THREAD_GIL_EXIT(); \ - g_main_context_iteration(g_main_context_get_thread_default(), TRUE); \ - MP_THREAD_GIL_ENTER(); \ -} while (0); - - -#include -#define MICROPY_UNIX_MACHINE_IDLE sched_yield(); diff --git a/bricks/ev3dev/mpconfigport.mk b/bricks/ev3dev/mpconfigport.mk deleted file mode 100644 index 55fc97680..000000000 --- a/bricks/ev3dev/mpconfigport.mk +++ /dev/null @@ -1,43 +0,0 @@ -# SPDX-License-Identifier: MIT -# Copyright (c) 2013, 2014 Damien P. George - -# Enable/disable modules and 3rd-party libs to be included in interpreter - -# Build 32-bit binaries on a 64-bit host -MICROPY_FORCE_32BIT = 0 - -# This variable can take the following values: -# 0 - no readline, just simple stdin input -# 1 - use MicroPython version of readline -MICROPY_USE_READLINE = 1 - -# btree module using Berkeley DB 1.xx -MICROPY_PY_BTREE = 1 - -# _thread module using pthreads -MICROPY_PY_THREAD = 1 - -# Subset of CPython termios module -MICROPY_PY_TERMIOS = 1 - -# Subset of CPython socket module -MICROPY_PY_SOCKET = 1 - -# ffi module requires libffi (libffi-dev Debian package) -MICROPY_PY_FFI = 1 - -# ussl module requires one of the TLS libraries below -MICROPY_PY_USSL = 1 -# axTLS has minimal size but implements only a subset of modern TLS -# functionality, so may have problems with some servers. -MICROPY_SSL_AXTLS = 1 -# mbedTLS is more up to date and complete implementation, but also -# more bloated. -MICROPY_SSL_MBEDTLS = 0 - -# jni module requires JVM/JNI -MICROPY_PY_JNI = 0 - -# Avoid using system libraries, use copies bundled with MicroPython -# as submodules (currently affects only libffi). -MICROPY_STANDALONE = 0 diff --git a/bricks/ev3dev/pb_ev3dev_types.h b/bricks/ev3dev/pb_ev3dev_types.h deleted file mode 100644 index 3fc5e398b..000000000 --- a/bricks/ev3dev/pb_ev3dev_types.h +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2019-2021 The Pybricks Authors - -#ifndef PYBRICKS_INCLUDED_BRICKS_EV3DEV_TYPES_H -#define PYBRICKS_INCLUDED_BRICKS_EV3DEV_TYPES_H - -#include - -#include "py/obj.h" - -// class Font - -// IMPORTANT: pb_type_ev3dev_Font_init() must be called before using -// pb_type_ev3dev_Font or pb_const_ev3dev_font_DEFAULT. It is safe to call -// pb_type_ev3dev_Font_init() more than once. -extern const mp_obj_type_t pb_type_ev3dev_Font; -#define pb_const_ev3dev_font_DEFAULT (MP_OBJ_FROM_PTR(&pb_const_ev3dev_Font_DEFAULT_obj)) -extern struct _ev3dev_Font_obj_t pb_const_ev3dev_Font_DEFAULT_obj; -void pb_type_ev3dev_Font_init(void); -GrxFont *pb_ev3dev_Font_obj_get_font(mp_const_obj_t obj); - - -// class Image - -extern const mp_obj_type_t pb_type_ev3dev_Image; - -// class Speaker - -extern const mp_obj_type_t pb_type_ev3dev_Speaker; - -#endif // PYBRICKS_INCLUDED_BRICKS_EV3DEV_TYPES_H diff --git a/bricks/ev3dev/pb_type_ev3dev_font.c b/bricks/ev3dev/pb_type_ev3dev_font.c deleted file mode 100644 index d082c5c9c..000000000 --- a/bricks/ev3dev/pb_type_ev3dev_font.c +++ /dev/null @@ -1,168 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2013, 2014 Damien P. George -// Copyright (c) 2019-2023 The Pybricks Authors - -// class Screen - -#include - -#include - -#include "py/mpconfig.h" -#include "py/misc.h" -#include "py/mpprint.h" -#include "py/obj.h" -#include "py/runtime.h" - -#include "pb_ev3dev_types.h" - -#include - -typedef struct _ev3dev_Font_obj_t { - mp_obj_base_t base; - GrxFont *font; - mp_obj_t family; - mp_obj_t style; - mp_obj_t width; - mp_obj_t height; -} ev3dev_Font_obj_t; - -ev3dev_Font_obj_t pb_const_ev3dev_Font_DEFAULT_obj; - -static void ev3dev_Font_init(ev3dev_Font_obj_t *self, GrxFont *font) { - self->base.type = &pb_type_ev3dev_Font; - self->font = font; - - const char *family = grx_font_get_family(font); - self->family = mp_obj_new_str(family, strlen(family)); - const char *style = grx_font_get_style(font); - self->style = mp_obj_new_str(style, strlen(style)); - self->width = mp_obj_new_int(grx_font_get_width(font)); - self->height = mp_obj_new_int(grx_font_get_height(font)); -} - -// This must be called from module.__init__() of module that includes this type -// otherwise we will crash when trying to access attributes! -void pb_type_ev3dev_Font_init(void) { - if (pb_const_ev3dev_Font_DEFAULT_obj.font) { - // already initialized - return; - } - - GError *error = NULL; - GrxFont *font = grx_font_load("Lucida", 12, &error); - if (!font) { - mp_obj_t ex = mp_obj_new_exception_msg_varg( - &mp_type_RuntimeError, "Failed to load default font: %s", error->message); - g_error_free(error); - nlr_raise(ex); - } - ev3dev_Font_init(&pb_const_ev3dev_Font_DEFAULT_obj, font); -} - -static mp_obj_t ev3dev_Font_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - enum { ARG_family, ARG_size, ARG_bold, ARG_monospace, ARG_lang, ARG_script }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_family, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, - { MP_QSTR_size, MP_ARG_INT, {.u_int = 12} }, - { MP_QSTR_bold, MP_ARG_BOOL, {.u_bool = FALSE} }, - { MP_QSTR_monospace, MP_ARG_BOOL, {.u_bool = FALSE} }, - { MP_QSTR_lang, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, - { MP_QSTR_script, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, - }; - - mp_arg_val_t arg_vals[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, arg_vals); - - const char *family = NULL; - if (arg_vals[ARG_family].u_obj != mp_const_none) { - family = mp_obj_str_get_str(arg_vals[ARG_family].u_obj); - } - - mp_int_t size = arg_vals[ARG_size].u_int; - mp_int_t dpi = -1; // use screen dpi - GrxFontWeight weight = arg_vals[ARG_bold].u_bool ? GRX_FONT_WEIGHT_BOLD : GRX_FONT_WEIGHT_REGULAR; - GrxFontSlant slant = GRX_FONT_SLANT_REGULAR; - GrxFontWidth width = GRX_FONT_WIDTH_REGULAR; - bool monospace = arg_vals[ARG_monospace].u_bool; - - const char *lang = NULL; - if (arg_vals[ARG_lang].u_obj != mp_const_none) { - lang = mp_obj_str_get_str(arg_vals[ARG_lang].u_obj); - } - - const char *script = NULL; - if (arg_vals[ARG_script].u_obj != mp_const_none) { - script = mp_obj_str_get_str(arg_vals[ARG_script].u_obj); - if (strlen(script) != 4) { - mp_raise_ValueError(MP_ERROR_TEXT("script code must have 4 characters")); - } - } - - GError *error = NULL; - GrxFont *font = grx_font_load_full( - family, size, dpi, weight, slant, width, monospace, lang, script, &error); - if (!font) { - mp_obj_t ex = mp_obj_new_exception_msg_varg( - &mp_type_RuntimeError, "Failed to load font: %s", error->message); - g_error_free(error); - nlr_raise(ex); - } - - ev3dev_Font_obj_t *self = m_new_obj_with_finaliser(ev3dev_Font_obj_t); - ev3dev_Font_init(self, font); - - return MP_OBJ_FROM_PTR(self); -} - -static mp_obj_t ev3dev_Font___del__(mp_obj_t self_in) { - ev3dev_Font_obj_t *self = MP_OBJ_TO_PTR(self_in); - grx_font_unref(self->font); - - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_1(ev3dev_Font___del___obj, ev3dev_Font___del__); - -static mp_obj_t ev3dev_Font_text_width(mp_obj_t self_in, mp_obj_t text_in) { - ev3dev_Font_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_int(grx_font_get_text_width(self->font, mp_obj_str_get_str(text_in))); -} -static MP_DEFINE_CONST_FUN_OBJ_2(ev3dev_Font_text_width_obj, ev3dev_Font_text_width); - -static mp_obj_t ev3dev_Font_text_height(mp_obj_t self_in, mp_obj_t text_in) { - ev3dev_Font_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_int(grx_font_get_text_height(self->font, mp_obj_str_get_str(text_in))); -} -static MP_DEFINE_CONST_FUN_OBJ_2(ev3dev_Font_text_height_obj, ev3dev_Font_text_height); - -static const pb_attr_dict_entry_t ev3dev_Font_attr_dict[] = { - PB_DEFINE_CONST_ATTR_RO(MP_QSTR_family, ev3dev_Font_obj_t, family), - PB_DEFINE_CONST_ATTR_RO(MP_QSTR_style, ev3dev_Font_obj_t, style), - PB_DEFINE_CONST_ATTR_RO(MP_QSTR_width, ev3dev_Font_obj_t, width), - PB_DEFINE_CONST_ATTR_RO(MP_QSTR_height, ev3dev_Font_obj_t, height), - PB_ATTR_DICT_SENTINEL -}; - -static const mp_rom_map_elem_t ev3dev_Font_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_DEFAULT), MP_ROM_PTR(&pb_const_ev3dev_Font_DEFAULT_obj) }, - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&ev3dev_Font___del___obj) }, - { MP_ROM_QSTR(MP_QSTR_text_width), MP_ROM_PTR(&ev3dev_Font_text_width_obj) }, - { MP_ROM_QSTR(MP_QSTR_text_height), MP_ROM_PTR(&ev3dev_Font_text_height_obj) }, -}; -static MP_DEFINE_CONST_DICT(ev3dev_Font_locals_dict, ev3dev_Font_locals_dict_table); - -MP_DEFINE_CONST_OBJ_TYPE(pb_type_ev3dev_Font, - MP_QSTR_Font, - MP_TYPE_FLAG_NONE, - make_new, ev3dev_Font_make_new, - attr, pb_attribute_handler, - protocol, ev3dev_Font_attr_dict, - locals_dict, &ev3dev_Font_locals_dict); - -GrxFont *pb_ev3dev_Font_obj_get_font(mp_const_obj_t obj) { - if (!mp_obj_is_type(obj, &pb_type_ev3dev_Font)) { - mp_raise_TypeError(MP_ERROR_TEXT("Requires Font object")); - } - ev3dev_Font_obj_t *self = MP_OBJ_TO_PTR(obj); - return self->font; -} diff --git a/bricks/ev3dev/pb_type_ev3dev_image.c b/bricks/ev3dev/pb_type_ev3dev_image.c deleted file mode 100644 index b33e3a1d3..000000000 --- a/bricks/ev3dev/pb_type_ev3dev_image.c +++ /dev/null @@ -1,581 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2013, 2014 Damien P. George -// Copyright (c) 2019-2023 The Pybricks Authors - -// class Image -// -// Image manipulation on ev3dev using the GRX3 graphics library. This can be -// used for both in-memory images and writing directly to the screen. - -#include - -#include - -#include - -#include "py/mpconfig.h" -#include "py/misc.h" -#include "py/mpprint.h" -#include "py/obj.h" -#include "py/objstr.h" -#include "py/runtime.h" - -#include "pb_ev3dev_types.h" - -#include -#include -#include - -typedef struct _ev3dev_Image_obj_t { - mp_obj_base_t base; - mp_obj_t width; - mp_obj_t height; - mp_obj_t buffer; // only used by _screen_ - gboolean cleared; // only used by _screen_ - GrxContext *context; - void *mem; // don't touch - needed for GC pressure - GrxTextOptions *text_options; - gint print_x; - gint print_y; -} ev3dev_Image_obj_t; - -// map Pybricks color type to GRX color value. -static GrxColor map_color(mp_obj_t obj) { - if (obj == mp_const_none) { - return GRX_COLOR_NONE; - } - - pbio_color_rgb_t rgb; - pbio_color_hsv_to_rgb(pb_type_Color_get_hsv(obj), &rgb); - return grx_color_get(rgb.r, rgb.g, rgb.b); -} - -static mp_obj_t ev3dev_Image_new(GrxContext *context) { - ev3dev_Image_obj_t *self = m_new_obj_with_finaliser(ev3dev_Image_obj_t); - - self->base.type = &pb_type_ev3dev_Image; - self->context = context; - self->mem = context->frame.base_address.plane0; - self->width = mp_obj_new_int(grx_context_get_width(self->context)); - self->height = mp_obj_new_int(grx_context_get_height(self->context)); - - pb_type_ev3dev_Font_init(); - GrxFont *font = pb_ev3dev_Font_obj_get_font(pb_const_ev3dev_font_DEFAULT); - self->text_options = grx_text_options_new(font, GRX_COLOR_BLACK); - - // only the screen needs to be cleared on first use - self->cleared = context != grx_get_screen_context(); - - return MP_OBJ_FROM_PTR(self); -} - -static mp_obj_t ev3dev_Image_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - enum { ARG_source, ARG_sub, ARG_x1, ARG_y1, ARG_x2, ARG_y2 }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_source, MP_ARG_REQUIRED | MP_ARG_OBJ, { } }, - { MP_QSTR_sub, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = FALSE} }, - { MP_QSTR_x1, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, - { MP_QSTR_y1, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, - { MP_QSTR_x2, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, - { MP_QSTR_y2, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, - }; - - mp_arg_val_t arg_vals[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, arg_vals); - - GrxContext *context = NULL; - - mp_obj_t source_in = arg_vals[ARG_source].u_obj; - if (mp_obj_is_qstr(source_in) && MP_OBJ_QSTR_VALUE(source_in) == MP_QSTR__screen_) { - // special case '_screen_' creates image that draws directly to screen - context = grx_context_ref(grx_get_screen_context()); - } else if (mp_obj_is_str(source_in)) { - const char *filename = mp_obj_str_get_str(source_in); - - // add file extension if missing - char *filename_ext = NULL; - if (!g_str_has_suffix(filename, ".png") && !g_str_has_suffix(filename, ".PNG")) { - filename_ext = g_strconcat(filename, ".png", NULL); - filename = filename_ext; - } - - gint w, h; - if (!grx_query_png_file(filename, &w, &h)) { - mp_obj_t ex = mp_obj_new_exception_msg_varg(&mp_type_OSError, - MP_ERROR_TEXT("'%s' is not a .png file"), filename); - g_free(filename_ext); - nlr_raise(ex); - } - - GrxFrameMemory mem; - mem.plane0 = m_malloc(grx_screen_get_context_size(w, h)); - context = grx_context_new(w, h, &mem, NULL); - if (!context) { - g_free(filename_ext); - mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("failed to allocate context for image")); - } - - GError *error = NULL; - if (!grx_context_load_from_png(context, filename, FALSE, &error)) { - mp_obj_t ex = mp_obj_new_exception_msg_varg(&mp_type_OSError, - MP_ERROR_TEXT("Failed to load '%s': %s"), filename, error->message); - g_free(filename_ext); - g_error_free(error); - nlr_raise(ex); - } - - g_free(filename_ext); - } else if (mp_obj_is_type(source_in, &pb_type_ev3dev_Image)) { - ev3dev_Image_obj_t *image = MP_OBJ_TO_PTR(source_in); - if (arg_vals[ARG_sub].u_bool) { - mp_int_t x1 = pb_obj_get_int(arg_vals[ARG_x1].u_obj); - mp_int_t y1 = pb_obj_get_int(arg_vals[ARG_y1].u_obj); - mp_int_t x2 = pb_obj_get_int(arg_vals[ARG_x2].u_obj); - mp_int_t y2 = pb_obj_get_int(arg_vals[ARG_y2].u_obj); - context = grx_context_new_subcontext(x1, y1, x2, y2, image->context, NULL); - } else { - gint w = grx_context_get_width(image->context); - gint h = grx_context_get_height(image->context); - GrxFrameMemory mem; - mem.plane0 = m_malloc(grx_screen_get_context_size(w, h)); - context = grx_context_new(w, h, &mem, NULL); - grx_context_bit_blt(context, 0, 0, image->context, 0, 0, - w - 1, h - 1, GRX_COLOR_MODE_WRITE); - } - } - - if (!context) { - mp_raise_TypeError(MP_ERROR_TEXT("Argument must be str or Image")); - } - - return ev3dev_Image_new(context); -} - -static mp_obj_t ev3dev_Image_empty(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_width, ARG_height }; - const mp_arg_t allowed_args[] = { - { MP_QSTR_width, MP_ARG_OBJ, { .u_obj = mp_obj_new_int(grx_get_screen_width())} }, - { MP_QSTR_height, MP_ARG_OBJ, { .u_obj = mp_obj_new_int(grx_get_screen_height())} }, - }; - - mp_arg_val_t arg_vals[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, arg_vals); - - mp_int_t width = pb_obj_get_int(arg_vals[ARG_width].u_obj); - mp_int_t height = pb_obj_get_int(arg_vals[ARG_height].u_obj); - if (width <= 0 || height <= 0) { - mp_raise_ValueError(MP_ERROR_TEXT("width and height must be greater than 0")); - } - GrxFrameMemory mem; - mem.plane0 = m_malloc(grx_screen_get_context_size(width, height)); - GrxContext *context = grx_context_new(width, height, &mem, NULL); - if (!context) { - mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Failed to create graphics context")); - } - grx_context_clear(context, GRX_COLOR_WHITE); - return ev3dev_Image_new(context); -} -static MP_DEFINE_CONST_FUN_OBJ_KW(ev3dev_Image_empty_fun_obj, 0, ev3dev_Image_empty); -static MP_DEFINE_CONST_STATICMETHOD_OBJ(ev3dev_Image_empty_obj, MP_ROM_PTR(&ev3dev_Image_empty_fun_obj)); - -static mp_obj_t ev3dev_Image___del__(mp_obj_t self_in) { - ev3dev_Image_obj_t *self = MP_OBJ_TO_PTR(self_in); - grx_text_options_unref(self->text_options); - grx_context_unref(self->context); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_1(ev3dev_Image___del___obj, ev3dev_Image___del__); - -// Ensure that screen has been cleared before we start drawing anything else -static void clear_once(ev3dev_Image_obj_t *self) { - if (self->cleared) { - return; - } - grx_context_clear(self->context, GRX_COLOR_WHITE); - self->cleared = TRUE; -} - -static mp_obj_t ev3dev_Image_clear(mp_obj_t self_in) { - ev3dev_Image_obj_t *self = MP_OBJ_TO_PTR(self_in); - clear_once(self); - grx_context_clear(self->context, GRX_COLOR_WHITE); - self->print_x = 0; - self->print_y = 0; - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_1(ev3dev_Image_clear_obj, ev3dev_Image_clear); - -static mp_obj_t ev3dev_Image_draw_pixel(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args, - ev3dev_Image_obj_t, self, - PB_ARG_REQUIRED(x), - PB_ARG_REQUIRED(y), - PB_ARG_DEFAULT_OBJ(color, pb_Color_BLACK_obj)); - - mp_int_t x = pb_obj_get_int(x_in); - mp_int_t y = pb_obj_get_int(y_in); - GrxColor color = map_color(color_in); - - clear_once(self); - grx_set_current_context(self->context); - grx_draw_pixel(x, y, color); - - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_KW(ev3dev_Image_draw_pixel_obj, 1, ev3dev_Image_draw_pixel); - -static mp_obj_t ev3dev_Image_draw_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args, - ev3dev_Image_obj_t, self, - PB_ARG_REQUIRED(x1), - PB_ARG_REQUIRED(y1), - PB_ARG_REQUIRED(x2), - PB_ARG_REQUIRED(y2), - PB_ARG_DEFAULT_INT(width, 1), - PB_ARG_DEFAULT_OBJ(color, pb_Color_BLACK_obj)); - - mp_int_t x1 = pb_obj_get_int(x1_in); - mp_int_t y1 = pb_obj_get_int(y1_in); - mp_int_t x2 = pb_obj_get_int(x2_in); - mp_int_t y2 = pb_obj_get_int(y2_in); - mp_int_t width = pb_obj_get_int(width_in); - GrxColor color = map_color(color_in); - - clear_once(self); - grx_set_current_context(self->context); - if (width == 1) { - grx_draw_line(x1, y1, x2, y2, color); - } else { - GrxLineOptions options = { .color = color, .width = width }; - grx_draw_line_with_options(x1, y1, x2, y2, &options); - } - - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_KW(ev3dev_Image_draw_line_obj, 1, ev3dev_Image_draw_line); - -static mp_obj_t ev3dev_Image_draw_box(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args, - ev3dev_Image_obj_t, self, - PB_ARG_REQUIRED(x1), - PB_ARG_REQUIRED(y1), - PB_ARG_REQUIRED(x2), - PB_ARG_REQUIRED(y2), - PB_ARG_DEFAULT_INT(r, 0), - PB_ARG_DEFAULT_FALSE(fill), - PB_ARG_DEFAULT_OBJ(color, pb_Color_BLACK_obj)); - - mp_int_t x1 = pb_obj_get_int(x1_in); - mp_int_t y1 = pb_obj_get_int(y1_in); - mp_int_t x2 = pb_obj_get_int(x2_in); - mp_int_t y2 = pb_obj_get_int(y2_in); - mp_int_t r = pb_obj_get_int(r_in); - GrxColor color = map_color(color_in); - - clear_once(self); - grx_set_current_context(self->context); - if (mp_obj_is_true(fill_in)) { - if (r > 0) { - grx_draw_filled_rounded_box(x1, y1, x2, y2, r, color); - } else { - grx_draw_filled_box(x1, y1, x2, y2, color); - } - } else { - if (r > 0) { - grx_draw_rounded_box(x1, y1, x2, y2, r, color); - } else { - grx_draw_box(x1, y1, x2, y2, color); - } - } - - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_KW(ev3dev_Image_draw_box_obj, 1, ev3dev_Image_draw_box); - -static mp_obj_t ev3dev_Image_draw_circle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args, - ev3dev_Image_obj_t, self, - PB_ARG_REQUIRED(x), - PB_ARG_REQUIRED(y), - PB_ARG_REQUIRED(r), - PB_ARG_DEFAULT_FALSE(fill), - PB_ARG_DEFAULT_OBJ(color, pb_Color_BLACK_obj)); - - mp_int_t x = pb_obj_get_int(x_in); - mp_int_t y = pb_obj_get_int(y_in); - mp_int_t r = pb_obj_get_int(r_in); - bool fill = mp_obj_is_true(fill_in); - GrxColor color = map_color(color_in); - - clear_once(self); - grx_set_current_context(self->context); - if (fill) { - grx_draw_filled_circle(x, y, r, color); - } else { - grx_draw_circle(x, y, r, color); - } - - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_KW(ev3dev_Image_draw_circle_obj, 1, ev3dev_Image_draw_circle); - -static mp_obj_t ev3dev_Image_draw_image(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args, - ev3dev_Image_obj_t, self, - PB_ARG_REQUIRED(x), - PB_ARG_REQUIRED(y), - PB_ARG_REQUIRED(source), - PB_ARG_DEFAULT_NONE(transparent)); - - mp_int_t x = pb_obj_get_int(x_in); - mp_int_t y = pb_obj_get_int(y_in); - if (mp_obj_is_str(source_in)) { - mp_obj_t args[1] = { source_in }; - source_in = ev3dev_Image_make_new(&pb_type_ev3dev_Image, 1, 0, args); - } - if (!mp_obj_is_type(source_in, &pb_type_ev3dev_Image)) { - mp_raise_TypeError(MP_ERROR_TEXT("Image object is required")); - } - ev3dev_Image_obj_t *source = MP_OBJ_TO_PTR(source_in); - GrxColor transparent = map_color(transparent_in); - - clear_once(self); - grx_context_bit_blt(self->context, x, y, source->context, 0, 0, - grx_context_get_max_x(source->context), grx_context_get_max_y(source->context), - transparent == GRX_COLOR_NONE ? GRX_COLOR_MODE_WRITE : grx_color_to_image_mode(transparent)); - - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_KW(ev3dev_Image_draw_image_obj, 1, ev3dev_Image_draw_image); - -static mp_obj_t ev3dev_Image_load_image(mp_obj_t self_in, mp_obj_t source_in) { - ev3dev_Image_obj_t *self = MP_OBJ_TO_PTR(self_in); - - if (mp_obj_is_str(source_in)) { - mp_obj_t args[1] = { source_in }; - source_in = ev3dev_Image_make_new(&pb_type_ev3dev_Image, 1, 0, args); - } - - if (!mp_obj_is_type(source_in, &pb_type_ev3dev_Image)) { - mp_raise_TypeError(MP_ERROR_TEXT("source must be Image or str")); - } - - ev3dev_Image_obj_t *source = MP_OBJ_TO_PTR(source_in); - - mp_obj_t x = mp_obj_new_int((mp_obj_get_int(self->width) - mp_obj_get_int(source->width)) / 2); - mp_obj_t y = mp_obj_new_int((mp_obj_get_int(self->height) - mp_obj_get_int(source->height)) / 2); - - // if the destination is the screen, then we double-buffer to prevent flicker - if (self->context == grx_get_screen_context()) { - if (self->buffer == MP_OBJ_NULL) { - mp_obj_t args[2] = { self->width, self->height }; - mp_map_t kw_args; - mp_map_init(&kw_args, 0); - self->buffer = ev3dev_Image_empty(MP_ARRAY_SIZE(args), args, &kw_args); - } - - ev3dev_Image_clear(self->buffer); - - mp_obj_t args[4] = { self->buffer, x, y, source_in }; - mp_map_t kw_args; - mp_map_init(&kw_args, 0); - ev3dev_Image_draw_image(MP_ARRAY_SIZE(args), args, &kw_args); - - source_in = self->buffer; - x = MP_OBJ_NEW_SMALL_INT(0); - y = MP_OBJ_NEW_SMALL_INT(0); - } else { - ev3dev_Image_clear(self_in); - } - - mp_obj_t args[4] = { self_in, x, y, source_in }; - mp_map_t kw_args; - mp_map_init(&kw_args, 0); - ev3dev_Image_draw_image(MP_ARRAY_SIZE(args), args, &kw_args); - - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(ev3dev_Image_load_image_obj, ev3dev_Image_load_image); - -static mp_obj_t ev3dev_Image_draw_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args, - ev3dev_Image_obj_t, self, - PB_ARG_REQUIRED(x), - PB_ARG_REQUIRED(y), - PB_ARG_REQUIRED(text), - PB_ARG_DEFAULT_OBJ(text_color, pb_Color_BLACK_obj), - PB_ARG_DEFAULT_NONE(background_color)); - - mp_int_t x = pb_obj_get_int(x_in); - mp_int_t y = pb_obj_get_int(y_in); - - if (!mp_obj_is_str_or_bytes(text_in)) { - vstr_t vstr; - mp_print_t print; - vstr_init_print(&vstr, 16, &print); - mp_obj_print_helper(&print, text_in, PRINT_STR); - text_in = mp_obj_new_str_from_vstr(&vstr); - } - - const char *text = mp_obj_str_get_str(text_in); - GrxColor text_color = map_color(text_color_in); - GrxColor background_color = map_color(background_color_in); - - clear_once(self); - grx_set_current_context(self->context); - grx_text_options_set_fg_color(self->text_options, text_color); - grx_text_options_set_bg_color(self->text_options, background_color); - if (background_color != GRX_COLOR_NONE) { - GrxFont *font = grx_text_options_get_font(self->text_options); - gint w = grx_font_get_text_width(font, text); - gint h = grx_font_get_text_height(font, text); - grx_draw_filled_box(x, y, x + w - 1, y + h - 1, background_color); - } - grx_draw_text(text, x, y, self->text_options); - - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_KW(ev3dev_Image_draw_text_obj, 1, ev3dev_Image_draw_text); - -static mp_obj_t ev3dev_Image_set_font(mp_obj_t self_in, mp_obj_t font_in) { - ev3dev_Image_obj_t *self = MP_OBJ_TO_PTR(self_in); - GrxFont *font = pb_ev3dev_Font_obj_get_font(font_in); - - grx_text_options_set_font(self->text_options, font); - - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(ev3dev_Image_set_font_obj, ev3dev_Image_set_font); - -// copy of mp_builtin_print modified to print to vstr -static mp_obj_t ev3dev_Image_print(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_sep, ARG_end }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_sep, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR__space_)} }, - { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR__0x0a_)} }, - }; - - // parse args (a union is used to reduce the amount of C stack that is needed) - union { - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - size_t len[2]; - } u; - mp_arg_parse_all(0, NULL, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, u.args); - - ev3dev_Image_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - - // extract the objects first because we are going to use the other part of the union - mp_obj_t sep = u.args[ARG_sep].u_obj; - mp_obj_t end = u.args[ARG_end].u_obj; - const char *sep_data = mp_obj_str_get_data(sep, &u.len[0]); - const char *end_data = mp_obj_str_get_data(end, &u.len[1]); - - vstr_t vstr; - mp_print_t print; - vstr_init_print(&vstr, 16, &print); - - for (size_t i = 1; i < n_args; i++) { - if (i > 1) { - mp_print_strn(&print, sep_data, u.len[0], 0, 0, 0); - } - mp_obj_print_helper(&print, pos_args[i], PRINT_STR); - } - mp_print_strn(&print, end_data, u.len[1], 0, 0, 0); - - clear_once(self); - grx_set_current_context(self->context); - grx_text_options_set_fg_color(self->text_options, GRX_COLOR_BLACK); - grx_text_options_set_bg_color(self->text_options, GRX_COLOR_WHITE); - GrxFont *font = grx_text_options_get_font(self->text_options); - gint font_height = grx_font_get_height(font); - gchar **lines = g_strsplit(vstr_null_terminated_str(&vstr), "\n", -1); - for (gchar **l = lines; *l; l++) { - // if this is not the first line, then we had a newline and need to advance - if (l != lines) { - self->print_x = 0; - self->print_y += font_height; - } - // if printing would run off of the bottom of the screen, scroll - // everything on the screen up enough to fit one more line - gint screen_height = grx_get_height(); - gint over = self->print_y + font_height - screen_height; - if (over > 0) { - gint max_x = grx_get_max_x(); - for (int y = 0; y < screen_height; y++) { - const GrxColor *scan_line = grx_get_scanline(0, max_x, y + over, NULL); - if (scan_line) { - grx_put_scanline(0, max_x, y, scan_line, GRX_COLOR_MODE_WRITE); - } else { - grx_draw_hline(0, max_x, y, GRX_COLOR_WHITE); - } - } - self->print_y -= over; - } - gint w = grx_font_get_text_width(font, *l); - gint h = grx_font_get_text_height(font, *l); - grx_draw_filled_box(self->print_x, self->print_y, - self->print_x + w - 1, self->print_y + h - 1, GRX_COLOR_WHITE); - grx_draw_text(*l, self->print_x, self->print_y, self->text_options); - self->print_x += w; - } - g_strfreev(lines); - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(ev3dev_Image_print_obj, 1, ev3dev_Image_print); - -static mp_obj_t ev3dev_Image_save(mp_obj_t self_in, mp_obj_t filename_in) { - ev3dev_Image_obj_t *self = MP_OBJ_TO_PTR(self_in); - const char *filename = mp_obj_str_get_str(filename_in); - - // add file extension if missing - char *filename_ext = NULL; - if (!g_str_has_suffix(filename, ".png") && !g_str_has_suffix(filename, ".PNG")) { - filename_ext = g_strconcat(filename, ".png", NULL); - filename = filename_ext; - } - - GError *error = NULL; - gboolean ok = grx_context_save_to_png(self->context, filename, &error); - g_free(filename_ext); - if (!ok) { - mp_obj_t ex = mp_obj_new_exception_msg_varg(&mp_type_OSError, - MP_ERROR_TEXT("Failed to save image: %s"), error->message); - g_error_free(error); - nlr_raise(ex); - } - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(ev3dev_Image_save_obj, ev3dev_Image_save); - -static const pb_attr_dict_entry_t ev3dev_Image_attr_dict[] = { - PB_DEFINE_CONST_ATTR_RO(MP_QSTR_width, ev3dev_Image_obj_t, width), - PB_DEFINE_CONST_ATTR_RO(MP_QSTR_height, ev3dev_Image_obj_t, height), - PB_ATTR_DICT_SENTINEL -}; - -static const mp_rom_map_elem_t ev3dev_Image_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_empty), MP_ROM_PTR(&ev3dev_Image_empty_obj) }, - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&ev3dev_Image___del___obj) }, - { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&ev3dev_Image_clear_obj) }, - { MP_ROM_QSTR(MP_QSTR_draw_pixel), MP_ROM_PTR(&ev3dev_Image_draw_pixel_obj) }, - { MP_ROM_QSTR(MP_QSTR_draw_line), MP_ROM_PTR(&ev3dev_Image_draw_line_obj) }, - { MP_ROM_QSTR(MP_QSTR_draw_box), MP_ROM_PTR(&ev3dev_Image_draw_box_obj) }, - { MP_ROM_QSTR(MP_QSTR_draw_circle), MP_ROM_PTR(&ev3dev_Image_draw_circle_obj) }, - { MP_ROM_QSTR(MP_QSTR_draw_image), MP_ROM_PTR(&ev3dev_Image_draw_image_obj) }, - { MP_ROM_QSTR(MP_QSTR_load_image), MP_ROM_PTR(&ev3dev_Image_load_image_obj) }, - { MP_ROM_QSTR(MP_QSTR_draw_text), MP_ROM_PTR(&ev3dev_Image_draw_text_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_font), MP_ROM_PTR(&ev3dev_Image_set_font_obj) }, - { MP_ROM_QSTR(MP_QSTR_print), MP_ROM_PTR(&ev3dev_Image_print_obj) }, - { MP_ROM_QSTR(MP_QSTR_save), MP_ROM_PTR(&ev3dev_Image_save_obj) }, -}; -static MP_DEFINE_CONST_DICT(ev3dev_Image_locals_dict, ev3dev_Image_locals_dict_table); - -MP_DEFINE_CONST_OBJ_TYPE(pb_type_ev3dev_Image, - MP_QSTR_Image, - MP_TYPE_FLAG_NONE, - make_new, ev3dev_Image_make_new, - attr, pb_attribute_handler, - protocol, ev3dev_Image_attr_dict, - locals_dict, &ev3dev_Image_locals_dict); diff --git a/bricks/ev3dev/pb_type_ev3dev_speaker.c b/bricks/ev3dev/pb_type_ev3dev_speaker.c deleted file mode 100644 index 48dee04ab..000000000 --- a/bricks/ev3dev/pb_type_ev3dev_speaker.c +++ /dev/null @@ -1,664 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2018-2023 The Pybricks Authors - -// class Speaker -// -// For creating sounds on ev3dev. -// -// There are two ways to create sounds. One is to use the "Beep" device to -// create tones with a given frequency. This is done using the Linux input -// device so that the sound is played on the EV3. The other is to use ALSA -// for PCM playback of sampled sounds. To keep the code simple, we just -// invoke `aplay` in a subprocess (same with espeak for text to speech). - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include "py/mpconfig.h" -#include "py/mphal.h" -#include "py/obj.h" -#include "py/runtime.h" - -#include "pb_ev3dev_types.h" -#include -#include - -#define EV3DEV_EV3_INPUT_DEV_PATH "/dev/input/by-path/platform-sound-event" - -typedef struct _ev3dev_Speaker_obj_t { - mp_obj_base_t base; - bool initialized; - int beep_fd; - char language[10]; - char voice[10]; - char voice_setting[21]; - char speed[8]; - char pitch[8]; - gboolean aplay_busy; - gboolean aplay_result; - GError *aplay_error; - gboolean espeak_busy; - gboolean espeak_result; - GError *espeak_error; - gboolean splice_busy; - gssize splice_result; - GError *splice_error; -} ev3dev_Speaker_obj_t; - -static ev3dev_Speaker_obj_t ev3dev_speaker_singleton; - - -static mp_obj_t ev3dev_Speaker_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - ev3dev_Speaker_obj_t *self = &ev3dev_speaker_singleton; - if (!self->initialized) { - self->base.type = &pb_type_ev3dev_Speaker; - self->beep_fd = open(EV3DEV_EV3_INPUT_DEV_PATH, O_RDWR, 0); - if (self->beep_fd == -1) { - perror("Failed to open input dev for sound, beep will not work"); - } - strncpy(self->language, "en", sizeof(self->language)); - strncpy(self->voice, "m1", sizeof(self->voice)); - strncpy(self->speed, "130", sizeof(self->speed)); - strncpy(self->pitch, "50", sizeof(self->pitch)); - - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_obj_t dest[4]; - mp_load_method(self, MP_QSTR_set_volume, dest); - dest[2] = MP_OBJ_NEW_SMALL_INT(100); - dest[3] = MP_ROM_QSTR(MP_QSTR__default_); - mp_call_method_n_kw(2, 0, dest); - nlr_pop(); - } else { - // ignore error - } - - self->initialized = true; - } - return MP_OBJ_FROM_PTR(self); -} - -static int set_beep_frequency(ev3dev_Speaker_obj_t *self, int32_t freq) { - struct input_event event = { - .type = EV_SND, - .code = SND_TONE, - .value = freq, - }; - int ret; - - do { - ret = write(self->beep_fd, &event, sizeof(event)); - } while (ret == -1 && errno == EINTR); - - return ret; -} - -// This is used when there is an unhandled exception in a program to make sure -// we stop beeping. -void _pb_ev3dev_speaker_beep_off(void) { - set_beep_frequency(&ev3dev_speaker_singleton, 0); -} - -static mp_obj_t ev3dev_Speaker_beep(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args, - ev3dev_Speaker_obj_t, self, - PB_ARG_DEFAULT_INT(frequency, 500), - PB_ARG_DEFAULT_INT(duration, 100)); - - mp_int_t frequency = pb_obj_get_int(frequency_in); - mp_int_t duration = pb_obj_get_int(duration_in); - - int ret = set_beep_frequency(self, frequency); - if (ret == -1) { - mp_raise_OSError(errno); - } - - if (duration < 0) { - return mp_const_none; - } - - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_hal_delay_ms(duration); - set_beep_frequency(self, 0); - nlr_pop(); - } else { - set_beep_frequency(self, 0); - nlr_jump(nlr.ret_val); - } - - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_KW(ev3dev_Speaker_beep_obj, 1, ev3dev_Speaker_beep); - -static void ev3dev_Speaker_play_note(ev3dev_Speaker_obj_t *self, mp_obj_t obj, int duration) { - const char *note = mp_obj_str_get_str(obj); - int pos = 0; - double freq; - bool release = true; - - // Note names can be A-G followed by optional # (sharp) or b (flat) or R for rest - switch (note[pos++]) { - case 'C': - switch (note[pos++]) { - case 'b': - mp_raise_ValueError(MP_ERROR_TEXT("'Cb' is not allowed")); - break; - case '#': - freq = 17.32; - break; - default: - pos--; - freq = 16.35; - break; - } - break; - case 'D': - switch (note[pos++]) { - case 'b': - freq = 17.32; - break; - case '#': - freq = 19.45; - break; - default: - pos--; - freq = 18.35; - break; - } - break; - case 'E': - switch (note[pos++]) { - case 'b': - freq = 19.45; - break; - case '#': - mp_raise_ValueError(MP_ERROR_TEXT("'E#' is not allowed")); - break; - default: - pos--; - freq = 20.60; - break; - } - break; - case 'F': - switch (note[pos++]) { - case 'b': - mp_raise_ValueError(MP_ERROR_TEXT("'Fb' is not allowed")); - break; - case '#': - freq = 23.12; - break; - default: - pos--; - freq = 21.83; - break; - } - break; - case 'G': - switch (note[pos++]) { - case 'b': - freq = 23.12; - break; - case '#': - freq = 25.96; - break; - default: - pos--; - freq = 24.50; - break; - } - break; - case 'A': - switch (note[pos++]) { - case 'b': - freq = 25.96; - break; - case '#': - freq = 29.14; - break; - default: - pos--; - freq = 27.50; - break; - } - break; - case 'B': - switch (note[pos++]) { - case 'b': - freq = 29.14; - break; - case '#': - mp_raise_ValueError(MP_ERROR_TEXT("'B#' is not allowed")); - break; - default: - pos--; - freq = 30.87; - break; - } - break; - case 'R': - freq = 0; - break; - default: - mp_raise_ValueError(MP_ERROR_TEXT("Missing note name A-G or R")); - break; - } - - // Note name must be followed by the octave number - if (freq != 0) { - int octave = note[pos++] - '0'; - if (octave < 2 || octave > 8) { - mp_raise_ValueError(MP_ERROR_TEXT("Missing octave number 2-8")); - } - freq *= 2 << octave; - } - - // '/' delimiter is required between octave and fraction - if (note[pos++] != '/') { - mp_raise_ValueError(MP_ERROR_TEXT("Missing '/'")); - } - - // The fractional size of the note, e.g. 4 = quarter note - int fraction = note[pos++] - '0'; - if (fraction < 0 || fraction > 9) { - mp_raise_ValueError(MP_ERROR_TEXT("Missing fractional value 1, 2, 4, 8, etc.")); - } - - // optional second digit - int fraction2 = note[pos++] - '0'; - if (fraction2 < 0 || fraction2 > 9) { - pos--; - } else { - fraction = fraction * 10 + fraction2; - } - - duration /= fraction; - - // optional decorations - - if (note[pos++] == '.') { - // dotted note has length extended by 1/2 - duration = 3 * duration / 2; - } else { - pos--; - } - - if (note[pos++] == '_') { - // note with tie/slur is not released - release = false; - } else { - pos--; - } - - set_beep_frequency(self, (int)freq); - - // Normally, we want there to be a period of no sound (release) so that - // notes are distinct instead of running together. To sound good, the - // release period is made proportional to duration of the note. - if (release) { - mp_hal_delay_ms(7 * duration / 8); - set_beep_frequency(self, 0); - mp_hal_delay_ms(duration / 8); - } else { - mp_hal_delay_ms(duration); - } -} - -static mp_obj_t ev3dev_Speaker_play_notes(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args, - ev3dev_Speaker_obj_t, self, - PB_ARG_REQUIRED(notes), - PB_ARG_DEFAULT_INT(tempo, 120)); - - // length of whole note in milliseconds = 4 quarter/whole * 60 s/min * 1000 ms/s / tempo quarter/min - int duration = 4 * 60 * 1000 / pb_obj_get_int(tempo_in); - - nlr_buf_t nlr; - mp_obj_t item; - mp_obj_t iterable = mp_getiter(notes_in, NULL); - if (nlr_push(&nlr) == 0) { - while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { - ev3dev_Speaker_play_note(self, item, duration); - } - // in case the last note has '_' - set_beep_frequency(self, 0); - nlr_pop(); - } else { - // ensure that sound stops if an exception is raised - set_beep_frequency(self, 0); - nlr_jump(nlr.ret_val); - } - - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_KW(ev3dev_Speaker_play_notes_obj, 1, ev3dev_Speaker_play_notes); - -static void ev3dev_Speaker_aplay_callback(GObject *source_object, GAsyncResult *res, gpointer user_data) { - GSubprocess *subprocess = G_SUBPROCESS(source_object); - ev3dev_Speaker_obj_t *self = user_data; - g_clear_error(&self->aplay_error); - self->aplay_result = g_subprocess_wait_check_finish(subprocess, res, &self->aplay_error); - self->aplay_busy = FALSE; -} - -static mp_obj_t ev3dev_Speaker_play_file(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args, - ev3dev_Speaker_obj_t, self, - PB_ARG_REQUIRED(file)); - - const char *file = mp_obj_str_get_str(file_in); - - // FIXME: This function needs to be protected agains re-entrancy to make it - // thread-safe. - - GError *error = NULL; - GSubprocess *aplay = g_subprocess_new( - G_SUBPROCESS_FLAGS_STDOUT_SILENCE | G_SUBPROCESS_FLAGS_STDERR_PIPE, - &error, "aplay", "-q", file, NULL); - if (!aplay) { - // This error is unexpected, so doesn't need to be "user-friendly" - mp_obj_t ex = mp_obj_new_exception_msg_varg(&mp_type_RuntimeError, - MP_ERROR_TEXT("Failed to spawn aplay: %s"), error->message); - g_error_free(error); - nlr_raise(ex); - } - - self->aplay_busy = TRUE; - g_subprocess_wait_check_async(aplay, NULL, ev3dev_Speaker_aplay_callback, self); - - // Play sound in non-blocking fashion. If an exception occurs during playback, - // we have to keep running the event loop until the async function has completed. - // This means there is small chance that multiple exceptions could be caught - // and only the last one will be re-raised. - mp_obj_t exception = MP_OBJ_NULL; - nlr_buf_t nlr; - do { - if (nlr_push(&nlr) == 0) { - MICROPY_EVENT_POLL_HOOK - nlr_pop(); - } else { - g_subprocess_force_exit(aplay); - exception = MP_OBJ_FROM_PTR(nlr.ret_val); - } - } while (self->aplay_busy); - - if (exception != MP_OBJ_NULL) { - g_object_unref(aplay); - nlr_raise(exception); - } - - if (!self->aplay_result) { - const char *err_msg = self->aplay_error->message; - - // If there is something in stderr, use that as the error message instead - // of error->message - GInputStream *stderr_stream = g_subprocess_get_stderr_pipe(aplay); - gchar stderr_bytes[4096]; - gsize bytes_read; - if (g_input_stream_read_all(stderr_stream, stderr_bytes, sizeof(stderr_bytes), &bytes_read, NULL, NULL)) { - if (bytes_read) { - err_msg = stderr_bytes; - stderr_bytes[bytes_read] = '\0'; // just in case - } - } - - mp_obj_t ex = mp_obj_new_exception_msg_varg(&mp_type_RuntimeError, - MP_ERROR_TEXT("Playing file failed: %s"), err_msg); - g_object_unref(aplay); - nlr_raise(ex); - } - - g_object_unref(aplay); - - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_KW(ev3dev_Speaker_play_file_obj, 1, ev3dev_Speaker_play_file); - -static void ev3dev_Speaker_espeak_callback(GObject *source_object, GAsyncResult *res, gpointer user_data) { - GSubprocess *subprocess = G_SUBPROCESS(source_object); - ev3dev_Speaker_obj_t *self = user_data; - g_clear_error(&self->espeak_error); - self->espeak_result = g_subprocess_wait_check_finish(subprocess, res, &self->espeak_error); - self->espeak_busy = FALSE; -} - -static void ev3dev_Speaker_splice_callback(GObject *source_object, GAsyncResult *res, gpointer user_data) { - GOutputStream *out_stream = G_OUTPUT_STREAM(source_object); - ev3dev_Speaker_obj_t *self = user_data; - g_clear_error(&self->splice_error); - self->splice_result = g_output_stream_splice_finish(out_stream, res, &self->splice_error); - self->splice_busy = FALSE; -} - -static mp_obj_t ev3dev_Speaker_say(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args, - ev3dev_Speaker_obj_t, self, - PB_ARG_REQUIRED(text)); - - const char *text = mp_obj_str_get_str(text_in); - - // FIXME: This function needs to be protected against re-entrancy to make it - // thread-safe. - - GError *error = NULL; - GSubprocess *espeak = g_subprocess_new( - G_SUBPROCESS_FLAGS_STDOUT_PIPE | G_SUBPROCESS_FLAGS_STDERR_PIPE, - &error, "espeak", "-a", "200", "-v", self->voice_setting, "-s", self->speed, - "-p", self->pitch, "--stdout", text, NULL); - if (!espeak) { - // This error is unexpected, so doesn't need to be "user-friendly" - mp_obj_t ex = mp_obj_new_exception_msg_varg(&mp_type_RuntimeError, - MP_ERROR_TEXT("Failed to spawn espeak: %s"), error->message); - g_error_free(error); - nlr_raise(ex); - } - - GSubprocess *aplay = g_subprocess_new( - G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_SILENCE | G_SUBPROCESS_FLAGS_STDERR_PIPE, - &error, "aplay", "-q", NULL); - if (!aplay) { - // This error is unexpected, so doesn't need to be "user-friendly" - mp_obj_t ex = mp_obj_new_exception_msg_varg(&mp_type_RuntimeError, - MP_ERROR_TEXT("Failed to spawn aplay: %s"), error->message); - g_error_free(error); - g_object_unref(espeak); - nlr_raise(ex); - } - - self->espeak_busy = TRUE; - g_subprocess_wait_check_async(espeak, NULL, ev3dev_Speaker_espeak_callback, self); - self->aplay_busy = TRUE; - g_subprocess_wait_check_async(aplay, NULL, ev3dev_Speaker_aplay_callback, self); - self->splice_busy = TRUE; - GOutputStream *out_stream = g_subprocess_get_stdin_pipe(aplay); - g_output_stream_splice_async(out_stream, g_subprocess_get_stdout_pipe(espeak), - G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, - G_PRIORITY_DEFAULT, NULL, ev3dev_Speaker_splice_callback, self); - - // Play sound in non-blocking fashion. If an exception occurs during playback, - // we have to keep running the event loop until the async function has completed. - // This means there is small chance that multiple exceptions could be caught - // and only the last one will be re-raised. - mp_obj_t exception = MP_OBJ_NULL; - nlr_buf_t nlr; - do { - if (nlr_push(&nlr) == 0) { - MICROPY_EVENT_POLL_HOOK - nlr_pop(); - } else { - g_subprocess_force_exit(espeak); - g_subprocess_force_exit(aplay); - exception = MP_OBJ_FROM_PTR(nlr.ret_val); - } - } while (self->espeak_busy || self->aplay_busy || self->splice_busy); - - if (exception != MP_OBJ_NULL) { - g_object_unref(aplay); - g_object_unref(espeak); - nlr_raise(exception); - } - - if (!self->aplay_result) { - const char *err_msg = self->aplay_error->message; - - // If there is something in stderr, use that as the error message instead - // of error->message - GInputStream *stderr_stream = g_subprocess_get_stderr_pipe(aplay); - gchar stderr_bytes[4096]; - gsize bytes_read; - if (g_input_stream_read_all(stderr_stream, stderr_bytes, sizeof(stderr_bytes), &bytes_read, NULL, NULL)) { - if (bytes_read) { - err_msg = stderr_bytes; - stderr_bytes[bytes_read] = '\0'; // just in case - } - } - - mp_obj_t ex = mp_obj_new_exception_msg_varg(&mp_type_RuntimeError, - MP_ERROR_TEXT("Saying text failed: %s"), err_msg); - g_object_unref(aplay); - g_object_unref(espeak); - nlr_raise(ex); - } - - if (!self->espeak_result) { - const char *err_msg = self->espeak_error->message; - - // If there is something in stderr, use that as the error message instead - // of error->message - GInputStream *stderr_stream = g_subprocess_get_stderr_pipe(espeak); - gchar stderr_bytes[4096]; - gsize bytes_read; - if (g_input_stream_read_all(stderr_stream, stderr_bytes, sizeof(stderr_bytes), &bytes_read, NULL, NULL)) { - if (bytes_read) { - err_msg = stderr_bytes; - stderr_bytes[bytes_read] = '\0'; // just in case - } - } - - mp_obj_t ex = mp_obj_new_exception_msg_varg(&mp_type_RuntimeError, - MP_ERROR_TEXT("Saying text failed: %s"), err_msg); - g_object_unref(aplay); - g_object_unref(espeak); - nlr_raise(ex); - } - - g_object_unref(aplay); - g_object_unref(espeak); - - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_KW(ev3dev_Speaker_say_obj, 1, ev3dev_Speaker_say); - -static mp_obj_t ev3dev_Speaker_set_speech_options(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args, - ev3dev_Speaker_obj_t, self, - PB_ARG_DEFAULT_NONE(language), - PB_ARG_DEFAULT_NONE(voice), - PB_ARG_DEFAULT_NONE(speed), - PB_ARG_DEFAULT_NONE(pitch)); - - if (language_in != mp_const_none) { - strncpy(self->language, mp_obj_str_get_str(language_in), sizeof(self->language)); - } - if (voice_in != mp_const_none) { - strncpy(self->voice, mp_obj_str_get_str(voice_in), sizeof(self->voice)); - } - snprintf(self->voice_setting, sizeof(self->voice_setting), "%s+%s", self->language, self->voice); - - if (speed_in != mp_const_none) { - snprintf(self->speed, sizeof(self->speed), INT_FMT, pb_obj_get_int(speed_in)); - } - if (pitch_in != mp_const_none) { - snprintf(self->pitch, sizeof(self->pitch), INT_FMT, pb_obj_get_int(pitch_in)); - } - - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_KW(ev3dev_Speaker_set_speech_options_obj, 1, ev3dev_Speaker_set_speech_options); - -static mp_obj_t ev3dev_Speaker_set_volume(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args, - ev3dev_Speaker_obj_t, self, - PB_ARG_REQUIRED(volume), - PB_ARG_DEFAULT_QSTR(which, _all_)); - - (void)self; // unused - - mp_int_t volume = pb_obj_get_pct(volume_in); - const char *which = mp_obj_str_get_str(which_in); - - // EV3 sound driver uses 0-256 for volume - volume = 256 * volume / 100; - - char amixer_stdin[64]; - - if (strcmp(which, "_default_") == 0) { - // internal value to set sane defaults (PCM 70%, Beep 30%). volume parameter is ignored. - snprintf(amixer_stdin, sizeof(amixer_stdin), "sset PCM 179 \nsset Beep 77\n"); - } else if (strcmp(which, "_all_") == 0) { - snprintf(amixer_stdin, sizeof(amixer_stdin), "sset PCM " INT_FMT " \nsset Beep " INT_FMT "\n", - volume, volume); - } else if (strcmp(which, "Beep") == 0) { - snprintf(amixer_stdin, sizeof(amixer_stdin), "sset Beep " INT_FMT "\n", volume); - } else if (strcmp(which, "PCM") == 0) { - snprintf(amixer_stdin, sizeof(amixer_stdin), "sset PCM " INT_FMT "\n", volume); - } else { - // Note: '_default_' isn't listed since it is considered an internal option - mp_raise_ValueError(MP_ERROR_TEXT("which must be one of '_all_', 'Beep', 'PCM'")); - } - - GError *error = NULL; - GSubprocess *amixer = g_subprocess_new( - G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_SILENCE | G_SUBPROCESS_FLAGS_STDERR_PIPE, - &error, "amixer", "-q", "--stdin", NULL); - if (!amixer) { - // This error is unexpected, so doesn't need to be "user-friendly" - mp_obj_t ex = mp_obj_new_exception_msg_varg(&mp_type_RuntimeError, - MP_ERROR_TEXT("Failed to spawn amixer: %s"), error->message); - g_error_free(error); - nlr_raise(ex); - } - char *amixer_stderr = NULL; - if (!g_subprocess_communicate_utf8(amixer, amixer_stdin, NULL, NULL, &amixer_stderr, &error)) { - const char *msg = amixer_stderr == NULL ? error->message : amixer_stderr; - mp_obj_t ex = mp_obj_new_exception_msg_varg(&mp_type_RuntimeError, - MP_ERROR_TEXT("Failed to set volume: %s"), msg); - g_free(amixer_stderr); - g_error_free(error); - g_object_unref(amixer); - nlr_raise(ex); - } - - g_free(amixer_stderr); - g_object_unref(amixer); - - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_KW(ev3dev_Speaker_set_volume_obj, 1, ev3dev_Speaker_set_volume); - -static const mp_rom_map_elem_t ev3dev_Speaker_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_beep), MP_ROM_PTR(&ev3dev_Speaker_beep_obj) }, - { MP_ROM_QSTR(MP_QSTR_play_notes), MP_ROM_PTR(&ev3dev_Speaker_play_notes_obj) }, - { MP_ROM_QSTR(MP_QSTR_play_file), MP_ROM_PTR(&ev3dev_Speaker_play_file_obj) }, - { MP_ROM_QSTR(MP_QSTR_say), MP_ROM_PTR(&ev3dev_Speaker_say_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_speech_options), MP_ROM_PTR(&ev3dev_Speaker_set_speech_options_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_volume), MP_ROM_PTR(&ev3dev_Speaker_set_volume_obj) }, -}; -static MP_DEFINE_CONST_DICT(ev3dev_Speaker_locals_dict, ev3dev_Speaker_locals_dict_table); - -MP_DEFINE_CONST_OBJ_TYPE(pb_type_ev3dev_Speaker, - MP_QSTR_Speaker, - MP_TYPE_FLAG_NONE, - make_new, ev3dev_Speaker_make_new, - locals_dict, &ev3dev_Speaker_locals_dict); diff --git a/bricks/ev3dev/pbinit.c b/bricks/ev3dev/pbinit.c deleted file mode 100644 index f1f4bea83..000000000 --- a/bricks/ev3dev/pbinit.c +++ /dev/null @@ -1,121 +0,0 @@ - -// SPDX-License-Identifier: MIT -// Copyright (c) 2018-2020 The Pybricks Authors - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include "py/mpconfig.h" -#include "py/mpthread.h" - -#include "pbinit.h" - -// Flag that indicates whether we are busy stopping the thread -static volatile bool stopping_thread = false; -static pthread_t task_caller_thread; - -// The background thread that keeps firing the task handler -static void *task_caller(void *arg) { - struct timespec ts; - ts.tv_sec = 0; - ts.tv_nsec = 3300000; - - while (!stopping_thread) { - MP_THREAD_GIL_ENTER(); - while (pbio_do_one_event()) { - } - MP_THREAD_GIL_EXIT(); - - clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL); - etimer_request_poll(); - } - - return NULL; -} - -// Pybricks initialization tasks -void pybricks_init(void) { - GError *error = NULL; - if (!grx_set_mode_default_graphics(FALSE, &error)) { - fprintf(stderr, "Could not initialize graphics. Be sure to run using `brickrun -r -- pybricks-micropython`.\n"); - exit(1); - } - grx_clear_screen(GRX_COLOR_WHITE); - - // Screen center - gint cx = grx_get_width() / 2; - gint cy = grx_get_height() / 2; - - // One side of the triangle - gint base = MIN(grx_get_width(), grx_get_height()) * 7 / 16; - - // Perfect circle around triangle: r = base / (2*cos(30)) - // Horizontal distance from center to circle: s = r * sin(30) - gint r = (base * 100) / 173; - gint s = r / 2; - - // Draw larger circle around triangle - gint width = 5; - gint cr = r * 3 / 2; - grx_draw_filled_circle(cx, cy, cr, GRX_COLOR_BLACK); - grx_draw_filled_circle(cx, cy, cr - width, GRX_COLOR_WHITE); - - GrxPoint triangle[] = { - { - // Upper left vertex - .x = cx - s, - .y = cy - base / 2 - }, - { - // Bottom left vertex - .x = cx - s, - .y = cy + base / 2 - }, - { - // Right vertex - .x = cx + r, - .y = cy - } - }; - grx_draw_filled_convex_polygon(G_N_ELEMENTS(triangle), triangle, GRX_COLOR_BLACK); - - pbio_init(); - extern void ev3dev_status_light_init(void); - ev3dev_status_light_init(); - pb_package_pybricks_init(true); - pthread_create(&task_caller_thread, NULL, task_caller, NULL); -} - -// Pybricks deinitialization tasks -void pybricks_deinit(void) { - // Signal motor thread to stop and wait for it to do so. - stopping_thread = true; - pthread_join(task_caller_thread, NULL); -} - -void pybricks_unhandled_exception(void) { - pbio_stop_all(false); - extern void _pb_ev3dev_speaker_beep_off(void); - _pb_ev3dev_speaker_beep_off(); -} diff --git a/bricks/ev3dev/pbinit.h b/bricks/ev3dev/pbinit.h deleted file mode 100644 index 72040986c..000000000 --- a/bricks/ev3dev/pbinit.h +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2018-2020 The Pybricks Authors - -#ifndef MICROPY_INCLUDED_PBINIT_H -#define MICROPY_INCLUDED_PBINIT_H - -void pybricks_init(void); - -void pybricks_deinit(void); - -#endif // MICROPY_INCLUDED_PBINIT_H diff --git a/bricks/ev3dev/pbsmbus.c b/bricks/ev3dev/pbsmbus.c deleted file mode 100644 index e22bb75b1..000000000 --- a/bricks/ev3dev/pbsmbus.c +++ /dev/null @@ -1,156 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2019-2020 The Pybricks Authors - -#include -#include -#include -#include -#include - -#include -#include -// i2ctools v4 moved smbus functions to a new header file -#if PB_HAVE_LIBI2C -#include -#endif - -#include - -#include "pbsmbus.h" - -#define MAXDEVPATH (16) -#define BUS_NUM_MIN (3) -#define BUS_NUM_MAX (6) - -struct _smbus_t { - int file; - int address; -}; - -smbus_t buses[BUS_NUM_MAX - BUS_NUM_MIN + 1]; - -static pbio_error_t pb_smbus_set_address(smbus_t *bus, int address) { - - if (bus->address != address) { - if (ioctl(bus->file, I2C_SLAVE, address) != 0) { - return PBIO_ERROR_IO; - } - bus->address = address; - } - - return PBIO_SUCCESS; -} - -pbio_error_t pb_smbus_get(smbus_t **_bus, int bus_num) { - - if (bus_num < BUS_NUM_MIN || bus_num > BUS_NUM_MAX) { - return PBIO_ERROR_INVALID_ARG; - } - - smbus_t *bus = &buses[bus_num - BUS_NUM_MIN]; - - char devpath[MAXDEVPATH]; - - if (snprintf(devpath, MAXDEVPATH, "/dev/i2c-%d", bus_num) >= MAXDEVPATH) { - return PBIO_ERROR_IO; - } - - bus->file = open(devpath, O_RDWR, 0); - bus->address = -1; - - if (bus->file == -1) { - return PBIO_ERROR_IO; - } - - *_bus = bus; - - return PBIO_SUCCESS; -} - -pbio_error_t pb_smbus_read_bytes(smbus_t *bus, uint8_t address, uint8_t reg, uint8_t len, uint8_t *buf) { - - pbio_error_t err = pb_smbus_set_address(bus, address); - if (err != PBIO_SUCCESS) { - return err; - } - - int rclen = i2c_smbus_read_i2c_block_data(bus->file, reg, len, buf); - if (rclen != len) { - return PBIO_ERROR_IO; - } - - return PBIO_SUCCESS; -} - -pbio_error_t pb_smbus_write_bytes(smbus_t *bus, uint8_t address, uint8_t reg, uint8_t len, const uint8_t *buf) { - - pbio_error_t err = pb_smbus_set_address(bus, address); - if (err != PBIO_SUCCESS) { - return err; - } - - if (i2c_smbus_write_i2c_block_data(bus->file, reg, len, buf) != 0) { - return PBIO_ERROR_IO; - } - - return PBIO_SUCCESS; -} - -pbio_error_t pb_smbus_read_no_reg(smbus_t *bus, uint8_t address, uint8_t *buf) { - - pbio_error_t err = pb_smbus_set_address(bus, address); - if (err != PBIO_SUCCESS) { - return err; - } - - int result = i2c_smbus_read_byte(bus->file); - - if (result < 0) { - return PBIO_ERROR_IO; - } - *buf = (uint8_t)result; - - return PBIO_SUCCESS; -} - -pbio_error_t pb_smbus_write_no_reg(smbus_t *bus, uint8_t address, uint8_t buf) { - - pbio_error_t err = pb_smbus_set_address(bus, address); - if (err != PBIO_SUCCESS) { - return err; - } - - if (i2c_smbus_write_byte(bus->file, buf) != 0) { - return PBIO_ERROR_IO; - } - - return PBIO_SUCCESS; -} - -pbio_error_t pb_smbus_read_quick(smbus_t *bus, uint8_t address) { - - pbio_error_t err = pb_smbus_set_address(bus, address); - if (err != PBIO_SUCCESS) { - return err; - } - - if (i2c_smbus_write_quick(bus->file, I2C_SMBUS_READ) != 0) { - return PBIO_ERROR_IO; - } - - return PBIO_SUCCESS; -} - -pbio_error_t pb_smbus_write_quick(smbus_t *bus, uint8_t address) { - - pbio_error_t err = pb_smbus_set_address(bus, address); - if (err != PBIO_SUCCESS) { - return err; - } - - if (i2c_smbus_write_quick(bus->file, I2C_SMBUS_WRITE) != 0) { - return PBIO_ERROR_IO; - } - - return PBIO_SUCCESS; -} diff --git a/bricks/ev3dev/pbsmbus.h b/bricks/ev3dev/pbsmbus.h deleted file mode 100644 index 9c5bc19df..000000000 --- a/bricks/ev3dev/pbsmbus.h +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2019-2020 The Pybricks Authors - -#ifndef _PBSMBUS_H_ -#define _PBSMBUS_H_ - -#include -#if PB_HAVE_LIBI2C -#include -#else -#include -#endif -#include - -#define PB_SMBUS_BLOCK_MAX I2C_SMBUS_BLOCK_MAX - -typedef struct _smbus_t smbus_t; - -pbio_error_t pb_smbus_get(smbus_t **_bus, int bus_num); - -pbio_error_t pb_smbus_read_bytes(smbus_t *bus, uint8_t address, uint8_t reg, uint8_t len, uint8_t *buf); - -pbio_error_t pb_smbus_write_bytes(smbus_t *bus, uint8_t address, uint8_t reg, uint8_t len, const uint8_t *buf); - -pbio_error_t pb_smbus_read_no_reg(smbus_t *bus, uint8_t address, uint8_t *buf); - -pbio_error_t pb_smbus_write_no_reg(smbus_t *bus, uint8_t address, uint8_t buf); - -pbio_error_t pb_smbus_read_quick(smbus_t *bus, uint8_t address); - -pbio_error_t pb_smbus_write_quick(smbus_t *bus, uint8_t address); - -#endif /* _PBSMBUS_H_ */ diff --git a/bricks/nxt/mpconfigport.h b/bricks/nxt/mpconfigport.h index 2030ea5cf..f6dbae22d 100644 --- a/bricks/nxt/mpconfigport.h +++ b/bricks/nxt/mpconfigport.h @@ -33,7 +33,6 @@ #define PYBRICKS_PY_HUBS (1) #define PYBRICKS_PY_IODEVICES (0) #define PYBRICKS_PY_MEDIA (0) -#define PYBRICKS_PY_MEDIA_EV3DEV (0) #define PYBRICKS_PY_NXTDEVICES (1) #define PYBRICKS_PY_PARAMETERS (1) #define PYBRICKS_PY_PARAMETERS_BUTTON (1) diff --git a/bricks/primehub/mpconfigport.h b/bricks/primehub/mpconfigport.h index 3a7dd34c3..dba0a2a89 100644 --- a/bricks/primehub/mpconfigport.h +++ b/bricks/primehub/mpconfigport.h @@ -34,7 +34,6 @@ #define PYBRICKS_PY_IODEVICES (1) #define PYBRICKS_PY_IODEVICES_XBOX_CONTROLLER (1) #define PYBRICKS_PY_MEDIA (1) -#define PYBRICKS_PY_MEDIA_EV3DEV (0) #define PYBRICKS_PY_NXTDEVICES (0) #define PYBRICKS_PY_PARAMETERS (1) #define PYBRICKS_PY_PARAMETERS_BUTTON (1) diff --git a/bricks/technichub/mpconfigport.h b/bricks/technichub/mpconfigport.h index 0037196ff..4afa39575 100644 --- a/bricks/technichub/mpconfigport.h +++ b/bricks/technichub/mpconfigport.h @@ -32,7 +32,6 @@ #define PYBRICKS_PY_IODEVICES (1) #define PYBRICKS_PY_IODEVICES_XBOX_CONTROLLER (1) #define PYBRICKS_PY_MEDIA (0) -#define PYBRICKS_PY_MEDIA_EV3DEV (0) #define PYBRICKS_PY_NXTDEVICES (0) #define PYBRICKS_PY_PARAMETERS (1) #define PYBRICKS_PY_PARAMETERS_BUTTON (1) diff --git a/bricks/virtualhub/mpconfigvariant.h b/bricks/virtualhub/mpconfigvariant.h index 954157c14..c42a04949 100644 --- a/bricks/virtualhub/mpconfigvariant.h +++ b/bricks/virtualhub/mpconfigvariant.h @@ -27,7 +27,6 @@ #define PYBRICKS_PY_HUBS (1) #define PYBRICKS_PY_IODEVICES (1) #define PYBRICKS_PY_MEDIA (1) -#define PYBRICKS_PY_MEDIA_EV3DEV (0) #define PYBRICKS_PY_NXTDEVICES (0) #define PYBRICKS_PY_PARAMETERS (1) #define PYBRICKS_PY_PARAMETERS_BUTTON (1) @@ -71,8 +70,7 @@ #define MICROPY_HELPER_REPL (1) #define MICROPY_KBD_EXCEPTION (1) -// REVISIT: This list currently matches the stm32 builds. We may consider -// adding more like the ev3dev build. +// REVISIT: This list currently matches the stm32 builds. #define MICROPY_PY_UERRNO_LIST \ X(EPERM) \ X(EIO) \ diff --git a/lib/ev3dev/include/ev3dev_stretch/lego_motor.h b/lib/ev3dev/include/ev3dev_stretch/lego_motor.h deleted file mode 100644 index 8393199b3..000000000 --- a/lib/ev3dev/include/ev3dev_stretch/lego_motor.h +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2022 The Pybricks Authors - -#ifndef _PBIO_LEGO_MOTOR_H_ -#define _PBIO_LEGO_MOTOR_H_ - -#include - -#include -#include -#include - -pbio_error_t ev3dev_motor_setup(pbio_port_id_t port, bool is_servo); -pbio_error_t ev3dev_motor_get_id(pbio_port_id_t port, pbdrv_legodev_type_id_t *id); -pbio_error_t ev3dev_motor_run(pbio_port_id_t port, int duty_cycle); -pbio_error_t ev3dev_motor_stop(pbio_port_id_t port); - -#endif // _PBIO_LEGO_MOTOR_H_ diff --git a/lib/ev3dev/include/ev3dev_stretch/lego_port.h b/lib/ev3dev/include/ev3dev_stretch/lego_port.h deleted file mode 100644 index fd9eb3b84..000000000 --- a/lib/ev3dev/include/ev3dev_stretch/lego_port.h +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2018-2020 The Pybricks Authors - -#ifndef _PBIO_LEGO_PORT_H_ -#define _PBIO_LEGO_PORT_H_ - -#include - -#include -#include - -pbio_error_t ev3dev_lego_port_configure(pbio_port_id_t port, pbdrv_legodev_type_id_t id); - -#endif // _PBIO_LEGO_PORT_H_ diff --git a/lib/ev3dev/include/ev3dev_stretch/lego_sensor.h b/lib/ev3dev/include/ev3dev_stretch/lego_sensor.h deleted file mode 100644 index efa93975a..000000000 --- a/lib/ev3dev/include/ev3dev_stretch/lego_sensor.h +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2018-2020 The Pybricks Authors - -#ifndef _PBIO_LEGO_SENSOR_H_ -#define _PBIO_LEGO_SENSOR_H_ - -#include - -#include -#include - -/** - * Data types used by ev3dev sensors. - */ -typedef enum { - /** - * Signed 8-bit integer. - */ - LEGO_SENSOR_DATA_TYPE_INT8 = LUMP_DATA_TYPE_DATA8, - /** - * Little-endian, signed 16-bit integer. - */ - LEGO_SENSOR_DATA_TYPE_INT16 = LUMP_DATA_TYPE_DATA16, - /** - * Little-endian, signed 32-bit integer. - */ - LEGO_SENSOR_DATA_TYPE_INT32 = LUMP_DATA_TYPE_DATA32, - /** - * Little endian 32-bit floating point. - */ - LEGO_SENSOR_DATA_TYPE_FLOAT = LUMP_DATA_TYPE_DATAF, - /** - * Unsigned 8-bit integer. - */ - LEGO_SENSOR_DATA_TYPE_UINT8, - /** - * Unsigned 16-bit integer. - */ - LEGO_SENSOR_DATA_TYPE_UINT16, - /** - * Unsigned 32-bit integer. - */ - LEGO_SENSOR_DATA_TYPE_UINT32, - /** - * Big-endian, signed 16-bit integer. - */ - LEGO_SENSOR_DATA_TYPE_INT16_BE, -} lego_sensor_data_type_t; - -typedef struct _lego_sensor_t lego_sensor_t; - -pbio_error_t lego_sensor_get(lego_sensor_t **sensor, pbio_port_id_t port, pbdrv_legodev_type_id_t valid_id); - -pbio_error_t lego_sensor_get_info(lego_sensor_t *sensor, uint8_t *data_len, lego_sensor_data_type_t *data_type); - -pbio_error_t lego_sensor_get_bin_data(lego_sensor_t *sensor, uint8_t **bin_data); - -pbio_error_t lego_sensor_get_mode_id_from_str(lego_sensor_t *sensor, const char *mode_str, uint8_t *mode); - -pbio_error_t lego_sensor_get_mode(lego_sensor_t *sensor, uint8_t *mode); - -pbio_error_t lego_sensor_set_mode(lego_sensor_t *sensor, uint8_t mode); - -#endif // _PBIO_LEGO_SENSOR_H_ diff --git a/lib/ev3dev/include/ev3dev_stretch/nxtcolor.h b/lib/ev3dev/include/ev3dev_stretch/nxtcolor.h deleted file mode 100644 index 04c5c6399..000000000 --- a/lib/ev3dev/include/ev3dev_stretch/nxtcolor.h +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2019-2020 The Pybricks Authors - -#ifndef _PBIO_NXTCOLOR_H_ -#define _PBIO_NXTCOLOR_H_ - -#include - -#include -#include - -pbio_error_t nxtcolor_get_values_at_mode(pbio_port_id_t port, uint8_t mode, void *values); - -#endif // _PBIO_NXTCOLOR_H_ diff --git a/lib/ev3dev/include/ev3dev_stretch/sysfs.h b/lib/ev3dev/include/ev3dev_stretch/sysfs.h deleted file mode 100644 index 47634d84f..000000000 --- a/lib/ev3dev/include/ev3dev_stretch/sysfs.h +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2018-2020 The Pybricks Authors - -#ifndef _PBIO_EV3DEVSYSFS_H_ -#define _PBIO_EV3DEVSYSFS_H_ - -#include - -#include -#include - -pbio_error_t sysfs_get_number(pbio_port_id_t port, const char *rdir, int *sysfs_number); - -pbio_error_t sysfs_open(FILE **file, const char *pathpat, int n, const char *attribute, const char *rw); - -pbio_error_t sysfs_open_sensor_attr(FILE **file, int n, const char *attribute, const char *rw); - -pbio_error_t sysfs_open_tacho_motor_attr(FILE **file, int n, const char *attribute, const char *rw); - -pbio_error_t sysfs_open_dc_motor_attr(FILE **file, int n, const char *attribute, const char *rw); - -pbio_error_t sysfs_read_str(FILE *file, char *dest); - -pbio_error_t sysfs_write_str(FILE *file, const char *str); - -pbio_error_t sysfs_read_int(FILE *file, int *dest); - -pbio_error_t sysfs_write_int(FILE *file, int val); - - -#endif // _PBIO_EV3DEVSYSFS_H_ diff --git a/lib/ev3dev/src/ev3dev_stretch/lego_motor.c b/lib/ev3dev/src/ev3dev_stretch/lego_motor.c deleted file mode 100644 index 0ef43ff82..000000000 --- a/lib/ev3dev/src/ev3dev_stretch/lego_motor.c +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright (c) 2018-2020,2022 The Pybricks Authors - -// helper functions for managing ev3dev output ports - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#define MAX_PATH_LENGTH 120 - -typedef struct { - int n_motor; - bool connected; - bool coasting; - pbdrv_legodev_type_id_t id; - FILE *f_command; - FILE *f_duty; -} ev3dev_motor_t; - -static ev3dev_motor_t motors[PBDRV_CONFIG_LAST_MOTOR_PORT - PBDRV_CONFIG_FIRST_MOTOR_PORT + 1]; - -static pbio_error_t ev3dev_motor_init(ev3dev_motor_t *mtr, pbio_port_id_t port) { - - pbio_error_t err; - - // Start from not connected - mtr->connected = false; - - // Try to find tacho motor - err = sysfs_get_number(port, "/sys/class/tacho-motor", &mtr->n_motor); - if (err == PBIO_SUCCESS) { - // On success, open driver name - FILE *f_driver_name; - err = sysfs_open_tacho_motor_attr(&f_driver_name, mtr->n_motor, "driver_name", "r"); - if (err != PBIO_SUCCESS) { - return err; - } - // Read ID string - char driver_name[MAX_PATH_LENGTH]; - err = sysfs_read_str(f_driver_name, driver_name); - if (err != PBIO_SUCCESS) { - return err; - } - // Determine motor type ID - if (!strcmp(driver_name, "lego-ev3-l-motor")) { - mtr->id = PBDRV_LEGODEV_TYPE_ID_EV3_LARGE_MOTOR; - } else { - mtr->id = PBDRV_LEGODEV_TYPE_ID_EV3_MEDIUM_MOTOR; - } - // Close driver name file - if (fclose(f_driver_name) != 0) { - return PBIO_ERROR_IO; - } - // Open command file - err = sysfs_open_tacho_motor_attr(&mtr->f_command, mtr->n_motor, "command", "w"); - if (err != PBIO_SUCCESS) { - return err; - } - // Open duty file - err = sysfs_open_tacho_motor_attr(&mtr->f_duty, mtr->n_motor, "duty_cycle_sp", "w"); - if (err != PBIO_SUCCESS) { - return err; - - } - } - // If tacho-motor was not found, look for dc-motor instead - else if (err == PBIO_ERROR_NO_DEV) { - // Find dc-motor - err = sysfs_get_number(port, "/sys/class/dc-motor", &mtr->n_motor); - if (err != PBIO_SUCCESS) { - return err; - } - // On success, open relevant sysfs files and set ID type - mtr->id = PBDRV_LEGODEV_TYPE_ID_EV3DEV_DC_MOTOR; - // Open command - err = sysfs_open_dc_motor_attr(&mtr->f_command, mtr->n_motor, "command", "w"); - if (err != PBIO_SUCCESS) { - return err; - } - // Open duty - err = sysfs_open_dc_motor_attr(&mtr->f_duty, mtr->n_motor, "duty_cycle_sp", "w"); - if (err != PBIO_SUCCESS) { - return err; - } - } else { - // Could not find either type of motor, so return the error - return err; - } - // We have successfully connected - mtr->connected = true; - - // Now that we have found the motor, coast it - mtr->coasting = true; - return sysfs_write_str(mtr->f_command, "stop"); -} - -static pbio_error_t ev3dev_motor_connect_status(ev3dev_motor_t *mtr, pbio_error_t err) { - mtr->connected = err == PBIO_SUCCESS; - return err; -} - -/** - * Gets the motor reference for the given port. - * - * @param [out] mtr The motor reference. - * @param [in] port The requested port. - * @return Error code. - */ -static pbio_error_t ev3dev_motor_get(ev3dev_motor_t **mtr, pbio_port_id_t port) { - if (port < PBDRV_CONFIG_FIRST_MOTOR_PORT || port > PBDRV_CONFIG_LAST_MOTOR_PORT) { - return PBIO_ERROR_INVALID_ARG; - } - - *mtr = &motors[port - PBDRV_CONFIG_FIRST_MOTOR_PORT]; - - pbio_error_t err = PBIO_SUCCESS; - - if (!(*mtr)->connected) { - err = ev3dev_motor_init(*mtr, port); - } - - return ev3dev_motor_connect_status(*mtr, err); -} - -/** - * Sets up the motor port - * @param [in] port The motor port - * @param [out] is_servo Whether the expected motor type is a servo - * @return ::PBIO_SUCCESS if the call was successful, - * ::PBIO_ERROR_INVALID_ARG if port is not a valid port - * ::PBIO_ERROR_NO_DEV if port is valid but motor is not connected - * ::PBIO_ERROR_EAGAIN if this should be called again later - * ::PBIO_ERROR_IO if there was an I/O error - */ -pbio_error_t ev3dev_motor_setup(pbio_port_id_t port, bool is_servo) { - // Verify port - if (port < PBDRV_CONFIG_FIRST_MOTOR_PORT || port > PBDRV_CONFIG_LAST_MOTOR_PORT) { - return PBIO_ERROR_INVALID_ARG; - } - // Set connected status to false so we reinitialize later - motors[port - PBDRV_CONFIG_FIRST_MOTOR_PORT].connected = false; - - return ev3dev_lego_port_configure(port, - is_servo ? PBDRV_LEGODEV_TYPE_ID_EV3_LARGE_MOTOR : PBDRV_LEGODEV_TYPE_ID_EV3DEV_DC_MOTOR); -} - -/** - * Gets the motor type ID of the currently connected motor. - * - * @param [in] port The port the motor is attached to. - * @param [out] id The type identifier. - * @return Error code. - */ -pbio_error_t ev3dev_motor_get_id(pbio_port_id_t port, pbdrv_legodev_type_id_t *id) { - ev3dev_motor_t *mtr; - pbio_error_t err = ev3dev_motor_get(&mtr, port); - if (err != PBIO_SUCCESS) { - return err; - } - - *id = mtr->id; - - return ev3dev_motor_connect_status(mtr, PBIO_SUCCESS); -} - -/** - * Runs the motor using the "run-direct" command. - * - * @param [in] port The port the motor is attached to. - * @param [in] duty_cycle The requested duty cycle -100 to 100. - * @return Error code. - */ -pbio_error_t ev3dev_motor_run(pbio_port_id_t port, int duty_cycle) { - pbio_error_t err; - ev3dev_motor_t *mtr; - - err = ev3dev_motor_get(&mtr, port); - if (err != PBIO_SUCCESS) { - return err; - } - - // If we are coasting, we must first set the command to run-direct - if (mtr->coasting) { - err = sysfs_write_str(mtr->f_command, "run-direct"); - if (err != PBIO_SUCCESS) { - return ev3dev_motor_connect_status(mtr, err); - } - mtr->coasting = false; - } - - // Set the duty cycle value - err = sysfs_write_int(mtr->f_duty, duty_cycle); - if (err != PBIO_SUCCESS) { - return ev3dev_motor_connect_status(mtr, err); - } - - return PBIO_SUCCESS; -} - -/** - * Stops the motor using the "stop" command. - * - * @param [in] port The port the motor is attached to. - * @return Error code. - */ -pbio_error_t ev3dev_motor_stop(pbio_port_id_t port) { - pbio_error_t err; - ev3dev_motor_t *mtr; - - err = ev3dev_motor_get(&mtr, port); - if (err != PBIO_SUCCESS) { - return err; - } - - // Do nothing if we are already coasting - if (mtr->coasting) { - return PBIO_SUCCESS; - } - - // Send the stop command to trigger coast - mtr->coasting = true; - err = sysfs_write_str(mtr->f_command, "stop"); - if (err != PBIO_SUCCESS) { - return ev3dev_motor_connect_status(mtr, err); - } - - return PBIO_SUCCESS; -} diff --git a/lib/ev3dev/src/ev3dev_stretch/lego_port.c b/lib/ev3dev/src/ev3dev_stretch/lego_port.c deleted file mode 100644 index 8103ca817..000000000 --- a/lib/ev3dev/src/ev3dev_stretch/lego_port.c +++ /dev/null @@ -1,193 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2018-2020 The Pybricks Authors - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#define MAX_PATH_LENGTH 60 -#define MAX_READ_LENGTH "60" -#define BIN_DATA_SIZE 32 // size of bin_data sysfs attribute - -typedef enum { - NO_MOTOR, - NO_SENSOR, - AUTO, - NXT_ANALOG, - NXT_COLOR, - NXT_I2C, - OTHER_I2C, - EV3_ANALOG, - EV3_UART, - OTHER_UART, - RAW, - TACHO_MOTOR, - DC_MOTOR, - LED, -} ev3dev_lego_port_t; - -static const char* const port_modes[] = { - "no-motor", - "no-sensor", - "auto", - "nxt-analog", - "nxt-color", - "nxt-i2c", - "other-i2c", - "ev3-analog", - "ev3-uart", - "other-uart", - "raw", - "tacho-motor", - "dc-motor", - "led", -}; - -// Get the port mode -static pbio_error_t ev3dev_lego_port_get_mode(pbio_port_id_t port, const char *attribute, ev3dev_lego_port_t *port_mode) { - // Read lego-port number - int n_lport; - pbio_error_t err; - err = sysfs_get_number(port, "/sys/class/lego-port", &n_lport); - if (err != PBIO_SUCCESS) { - return err; - } - - // Get mode file path - char path[MAX_PATH_LENGTH]; - snprintf(path, MAX_PATH_LENGTH, "/sys/class/lego-port/port%d/%s", n_lport, attribute); - - // Open mode file for reading - char mode[12]; - FILE *f_mode = fopen(path, "r"); - if (f_mode == NULL) { - return PBIO_ERROR_IO; - } - // Read the current mode - if (fscanf(f_mode, "%" MAX_READ_LENGTH "s", mode) < 1) { - return PBIO_ERROR_IO; - } - // Close the mode file - if (fclose(f_mode) != 0) { - return PBIO_ERROR_IO; - } - - // Find matching port mode string - for (size_t i = 0; i < PBIO_ARRAY_SIZE(port_modes); i++) { - if (!strcmp(mode, port_modes[i])) { - *port_mode = i; - return PBIO_SUCCESS; - } - } - return PBIO_ERROR_IO; -} - -// Write the port mode without questions -static pbio_error_t ev3dev_lego_port_set_mode(pbio_port_id_t port, ev3dev_lego_port_t mode) { - - // Read lego-port number - int n_lport; - pbio_error_t err; - err = sysfs_get_number(port, "/sys/class/lego-port", &n_lport); - if (err != PBIO_SUCCESS) { - return err; - } - - // Mode file path - char p_mode[MAX_PATH_LENGTH]; - snprintf(p_mode, MAX_PATH_LENGTH, "/sys/class/lego-port/port%d/mode", n_lport); - // Open mode file for writing - FILE *f_port_mode = fopen(p_mode, "w"); - if (f_port_mode == NULL) { - return PBIO_ERROR_IO; - } - // Write mode - if (fprintf(f_port_mode, "%s", port_modes[mode]) != (int)strlen(port_modes[mode])) { - return PBIO_ERROR_IO; - } - // Close the mode file - if (fclose(f_port_mode) != 0) { - return PBIO_ERROR_IO; - } - return PBIO_SUCCESS; -} - -// Set compatible port configuration for given device -pbio_error_t ev3dev_lego_port_configure(pbio_port_id_t port, pbdrv_legodev_type_id_t id) { - pbio_error_t err; - - // Get the current port mode and status - ev3dev_lego_port_t mode_now, status_now; - err = ev3dev_lego_port_get_mode(port, "mode", &mode_now); - if (err != PBIO_SUCCESS) { - return err; - } - err = ev3dev_lego_port_get_mode(port, "status", &status_now); - if (err != PBIO_SUCCESS) { - return err; - } - - // If special modes have been set previously and they're still good, we're done. - if ((id == PBDRV_LEGODEV_TYPE_ID_NXT_COLOR_SENSOR && mode_now == RAW ) || - (id == PBDRV_LEGODEV_TYPE_ID_NXT_ANALOG && mode_now == NXT_ANALOG) || - (id == PBDRV_LEGODEV_TYPE_ID_NXT_TOUCH_SENSOR && status_now == NXT_ANALOG) || - (id == PBDRV_LEGODEV_TYPE_ID_NXT_SOUND_SENSOR && status_now == NXT_ANALOG) || - (id == PBDRV_LEGODEV_TYPE_ID_CUSTOM_I2C && mode_now == OTHER_I2C ) || - (id == PBDRV_LEGODEV_TYPE_ID_CUSTOM_UART && mode_now == OTHER_UART) || - (id == PBDRV_LEGODEV_TYPE_ID_ANY_LUMP_UART && status_now == EV3_UART) || - (id == PBDRV_LEGODEV_TYPE_ID_EV3DEV_DC_MOTOR && status_now == DC_MOTOR) - ){ - return PBIO_SUCCESS; - } - - // For undetected analog sensors, port must be set on first use - if (id == PBDRV_LEGODEV_TYPE_ID_NXT_ANALOG || id == PBDRV_LEGODEV_TYPE_ID_NXT_TOUCH_SENSOR) { - err = ev3dev_lego_port_set_mode(port, NXT_ANALOG); - return err == PBIO_SUCCESS ? PBIO_ERROR_AGAIN : err; - } - - // For Custom UART Sensors, port must be set on first use - if (id == PBDRV_LEGODEV_TYPE_ID_CUSTOM_UART) { - err = ev3dev_lego_port_set_mode(port, OTHER_UART); - return err == PBIO_SUCCESS ? PBIO_ERROR_AGAIN : err; - } - - // For Custom I2C Sensors, port must be set on first use - if (id == PBDRV_LEGODEV_TYPE_ID_CUSTOM_I2C) { - err = ev3dev_lego_port_set_mode(port, OTHER_I2C); - return err == PBIO_SUCCESS ? PBIO_ERROR_AGAIN : err; - } - - // For NXT 2.0 Color Sensor, port must be set to raw mode on first use - if (id == PBDRV_LEGODEV_TYPE_ID_NXT_COLOR_SENSOR) { - err = ev3dev_lego_port_set_mode(port, RAW); - return err == PBIO_SUCCESS ? PBIO_ERROR_AGAIN : err; - } - - // For DC Motors Sensor, port must be set to DC Motor on first use - if (id == PBDRV_LEGODEV_TYPE_ID_EV3DEV_DC_MOTOR) { - err = ev3dev_lego_port_set_mode(port, DC_MOTOR); - return err == PBIO_SUCCESS ? PBIO_ERROR_AGAIN : err; - } - - // For custom LUMP sensors, port must be set to EV3 UART on first use - if (id == PBDRV_LEGODEV_TYPE_ID_ANY_LUMP_UART) { - err = ev3dev_lego_port_set_mode(port, EV3_UART); - return err == PBIO_SUCCESS ? PBIO_ERROR_AGAIN : err; - } - - // For all other devices, the port should be in auto mode. - if (mode_now != AUTO) { - err = ev3dev_lego_port_set_mode(port, AUTO); - return err == PBIO_SUCCESS ? PBIO_ERROR_AGAIN : err; - } - return PBIO_SUCCESS; -} diff --git a/lib/ev3dev/src/ev3dev_stretch/lego_sensor.c b/lib/ev3dev/src/ev3dev_stretch/lego_sensor.c deleted file mode 100644 index 0a3f0e73d..000000000 --- a/lib/ev3dev/src/ev3dev_stretch/lego_sensor.c +++ /dev/null @@ -1,307 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2018-2020 The Pybricks Authors - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#define MAX_PATH_LENGTH 60 -#define MAX_READ_LENGTH "60" -#define BIN_DATA_SIZE 32 // size of bin_data sysfs attribute - -struct _lego_sensor_t { - int n_sensor; - int n_modes; - FILE *f_mode; - FILE *f_driver_name; - FILE *f_bin_data; - FILE *f_num_values; - FILE *f_bin_data_format; - char modes[12][17]; - uint8_t bin_data[PBDRV_LEGODEV_MAX_DATA_SIZE] __attribute__((aligned(32))); -}; -// Initialize an ev3dev sensor by opening the relevant sysfs attributes -static pbio_error_t ev3_sensor_init(lego_sensor_t *sensor, pbio_port_id_t port) { - pbio_error_t err; - - err = sysfs_get_number(port, "/sys/class/lego-sensor", &sensor->n_sensor); - if (err != PBIO_SUCCESS) { - return err; - } - - err = sysfs_open_sensor_attr(&sensor->f_driver_name, sensor->n_sensor, "driver_name", "r"); - if (err != PBIO_SUCCESS) { - return err; - } - - err = sysfs_open_sensor_attr(&sensor->f_mode, sensor->n_sensor, "mode", "r+"); - if (err != PBIO_SUCCESS) { - return err; - } - - err = sysfs_open_sensor_attr(&sensor->f_bin_data_format, sensor->n_sensor, "bin_data_format", "r"); - if (err != PBIO_SUCCESS) { - return err; - } - - err = sysfs_open_sensor_attr(&sensor->f_num_values, sensor->n_sensor, "num_values", "r"); - if (err != PBIO_SUCCESS) { - return err; - } - - err = sysfs_open_sensor_attr(&sensor->f_bin_data, sensor->n_sensor, "bin_data", "rb"); - if (err != PBIO_SUCCESS) { - return err; - } - - FILE *f_modes; - err = sysfs_open_sensor_attr(&f_modes, sensor->n_sensor, "modes", "r"); - if (err != PBIO_SUCCESS) { - return err; - } - - sensor->n_modes = 0; - while (fscanf(f_modes, " %16s", sensor->modes[sensor->n_modes]) == 1) { - sensor->n_modes++; - }; - if (fclose(f_modes) != 0) { - return PBIO_ERROR_IO; - } - - return PBIO_SUCCESS; -} - -// Get the device ID -static pbio_error_t ev3_sensor_get_id(lego_sensor_t *sensor, pbdrv_legodev_type_id_t *id) { - char driver_name[MAX_PATH_LENGTH]; - - pbio_error_t err = sysfs_read_str(sensor->f_driver_name, driver_name); - if (err != PBIO_SUCCESS) { - return err; - } - - if (!strcmp(driver_name, "lego-ev3-ir")) { - *id = PBDRV_LEGODEV_TYPE_ID_EV3_IR_SENSOR; - } - else if (!strcmp(driver_name, "lego-ev3-color")) { - *id = PBDRV_LEGODEV_TYPE_ID_EV3_COLOR_SENSOR; - } - else if (!strcmp(driver_name, "lego-ev3-touch")) { - *id = PBDRV_LEGODEV_TYPE_ID_EV3_TOUCH_SENSOR; - } - else if (!strcmp(driver_name, "lego-ev3-us")) { - *id = PBDRV_LEGODEV_TYPE_ID_EV3_ULTRASONIC_SENSOR; - } - else if (!strcmp(driver_name, "lego-ev3-gyro")) { - *id = PBDRV_LEGODEV_TYPE_ID_EV3_GYRO_SENSOR; - } - else if (!strcmp(driver_name, "nxt-analog")) { - *id = PBDRV_LEGODEV_TYPE_ID_NXT_ANALOG; - } - else if (!strcmp(driver_name, "lego-nxt-us")) { - *id = PBDRV_LEGODEV_TYPE_ID_NXT_ULTRASONIC_SENSOR; - } - else if (!strcmp(driver_name, "lego-nxt-touch")) { - *id = PBDRV_LEGODEV_TYPE_ID_NXT_TOUCH_SENSOR; - } - else if (!strcmp(driver_name, "lego-nxt-light")) { - *id = PBDRV_LEGODEV_TYPE_ID_NXT_LIGHT_SENSOR; - } - else if (!strcmp(driver_name, "lego-nxt-temp")) { - *id = PBDRV_LEGODEV_TYPE_ID_NXT_TEMPERATURE_SENSOR; - } - else if (!strcmp(driver_name, "lego-power-storage")) { - *id = PBDRV_LEGODEV_TYPE_ID_NXT_ENERGY_METER; - } - else { - *id = PBDRV_LEGODEV_TYPE_ID_NONE; - } - return PBIO_SUCCESS; -} - -// Get the device ID -static pbio_error_t ev3_sensor_assert_id(lego_sensor_t *sensor, pbdrv_legodev_type_id_t valid_id) { - - pbio_error_t err; - pbdrv_legodev_type_id_t id; - err = ev3_sensor_get_id(sensor, &id); - if (err != PBIO_SUCCESS) { - return err; - } - - // If we are here, we have already confirmed that a lego-sensor exists. - // So if the user asserts that this should be a LUMP or lego-sensor, this passes. - if (valid_id == PBDRV_LEGODEV_TYPE_ID_ANY_LUMP_UART || - valid_id == PBDRV_LEGODEV_TYPE_ID_EV3DEV_LEGO_SENSOR) { - return PBIO_SUCCESS; - } - - // If the detected ID matches the expected ID, return success. - if (id == valid_id) { - return PBIO_SUCCESS; - } - - // NXT Sound Sensors and NXT Touch Sensors without auto-id also pass as NXT Analog - if ((valid_id == PBDRV_LEGODEV_TYPE_ID_NXT_TOUCH_SENSOR && id == PBDRV_LEGODEV_TYPE_ID_NXT_ANALOG) || - (valid_id == PBDRV_LEGODEV_TYPE_ID_NXT_SOUND_SENSOR && id == PBDRV_LEGODEV_TYPE_ID_NXT_ANALOG)) { - return PBIO_SUCCESS; - } - return PBIO_ERROR_NO_DEV; -} - -struct _lego_sensor_t sensors[4]; - -// Get an ev3dev sensor -pbio_error_t lego_sensor_get(lego_sensor_t **sensor, pbio_port_id_t port, pbdrv_legodev_type_id_t valid_id) { - if (port < PBIO_PORT_ID_1 || port > PBIO_PORT_ID_4) { - return PBIO_ERROR_INVALID_ARG; - } - - *sensor = &sensors[port - PBIO_PORT_ID_1]; - - pbio_error_t err; - - // Initialize port if needed for this ID - err = ev3dev_lego_port_configure(port, valid_id); - if (err != PBIO_SUCCESS) { - return err; - } - - // For some custom sensors, there is no - // lego-sensor to initialize, so we're done. - if (valid_id == PBDRV_LEGODEV_TYPE_ID_CUSTOM_I2C || - valid_id == PBDRV_LEGODEV_TYPE_ID_CUSTOM_UART || - valid_id == PBDRV_LEGODEV_TYPE_ID_NXT_COLOR_SENSOR) { - return PBIO_SUCCESS; - } - - // Initialize sysfs - err = ev3_sensor_init(*sensor, port); - if (err != PBIO_SUCCESS) { - return err; - } - - // Assert that the expected device is attached - err = ev3_sensor_assert_id(*sensor, valid_id); - if (err != PBIO_SUCCESS) { - return err; - } - return PBIO_SUCCESS; -} - -// Get the device info -pbio_error_t lego_sensor_get_info(lego_sensor_t *sensor, uint8_t *data_len, lego_sensor_data_type_t *data_type) { - - pbio_error_t err; - - // Read data length attribute - int data_len_int; - err = sysfs_read_int(sensor->f_num_values, &data_len_int); - if (err != PBIO_SUCCESS) { - return err; - } - *data_len = data_len_int; - - // Read data type attribute - char s_data_type[MAX_PATH_LENGTH]; - err = sysfs_read_str(sensor->f_bin_data_format, s_data_type); - if (err != PBIO_SUCCESS) { - return err; - } - - // Convert data type identifier - if (!strcmp(s_data_type, "s8")) { - *data_type = LEGO_SENSOR_DATA_TYPE_INT8; - } - else if (!strcmp(s_data_type, "u8")) { - *data_type = LEGO_SENSOR_DATA_TYPE_UINT8; - } - else if (!strcmp(s_data_type, "s16")) { - *data_type = LEGO_SENSOR_DATA_TYPE_INT16; - } - else if (!strcmp(s_data_type, "u16")) { - *data_type = LEGO_SENSOR_DATA_TYPE_UINT16; - } - else if (!strcmp(s_data_type, "s32")) { - *data_type = LEGO_SENSOR_DATA_TYPE_INT32; - } - else if (!strcmp(s_data_type, "u32")) { - *data_type = LEGO_SENSOR_DATA_TYPE_UINT32; - } - else if (!strcmp(s_data_type, "s16_be")) { - *data_type = LEGO_SENSOR_DATA_TYPE_INT16_BE; - } - else if (!strcmp(s_data_type, "float")) { - *data_type = LEGO_SENSOR_DATA_TYPE_FLOAT; - } - else { - return PBIO_ERROR_FAILED; - } - - return PBIO_SUCCESS; -} - -// Get the mode id from string -pbio_error_t lego_sensor_get_mode_id_from_str(lego_sensor_t *sensor, const char *mode_str, uint8_t *mode) { - - // Find matching port mode string - for (size_t i = 0; i < PBIO_ARRAY_SIZE(sensor->modes); i++) { - if (!strcmp(mode_str, sensor->modes[i])) { - *mode = i; - return PBIO_SUCCESS; - } - } - - // Mode not found - return PBIO_ERROR_INVALID_ARG; -} - -// Get the current sensor mode -pbio_error_t lego_sensor_get_mode(lego_sensor_t *sensor, uint8_t *mode) { - - pbio_error_t err; - - // Read mode string - char mode_str[PBIO_ARRAY_SIZE(sensor->modes[0])]; - err = sysfs_read_str(sensor->f_mode, mode_str); - if (err != PBIO_SUCCESS) { - return err; - } - - // Return matching mode id - return lego_sensor_get_mode_id_from_str(sensor, mode_str, mode); -} - -// Set the sensor mode -pbio_error_t lego_sensor_set_mode(lego_sensor_t *sensor, uint8_t mode) { - - if (mode >= sensor->n_modes) { - return PBIO_ERROR_INVALID_ARG; - } - - return sysfs_write_str(sensor->f_mode, sensor->modes[mode]); -} - -// Read 32 bytes from bin_data attribute -pbio_error_t lego_sensor_get_bin_data(lego_sensor_t *sensor, uint8_t **bin_data) { - if (fseek(sensor->f_bin_data, 0, SEEK_SET) == -1) { - return PBIO_ERROR_IO; - } - - if (fread(sensor->bin_data, 1, BIN_DATA_SIZE, sensor->f_bin_data) < BIN_DATA_SIZE) { - return PBIO_ERROR_IO; - } - - *bin_data = sensor->bin_data; - - return PBIO_SUCCESS; -} diff --git a/lib/ev3dev/src/ev3dev_stretch/nxtcolor.c b/lib/ev3dev/src/ev3dev_stretch/nxtcolor.c deleted file mode 100644 index f4d569035..000000000 --- a/lib/ev3dev/src/ev3dev_stretch/nxtcolor.c +++ /dev/null @@ -1,537 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2019-2020 The Pybricks Authors - -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include -#include -#include - -#define IN (0) -#define OUT (1) - -#define min(a, b) ((a) < (b) ? (a) : (b)) -#define max(a, b) ((a) > (b) ? (a) : (b)) - -typedef struct { - const int digi0; // GPIO on wire 5 - const int digi1; // GPIO on wire 6 - const int adc_val; // ADC on wire 6 for getting reflection data - const int adc_con; // ADC on wire 1 for detecting sensor -} nxtcolor_pininfo_t; - -static const nxtcolor_pininfo_t pininfo[4] = { - [PBIO_PORT_ID_1 - PBIO_PORT_ID_1] = { - .digi0 = 2, - .digi1 = 15, - .adc_val = 5, - .adc_con = 6, - }, - [PBIO_PORT_ID_2 - PBIO_PORT_ID_1] = { - .digi0 = 14, - .digi1 = 13, - .adc_val = 7, - .adc_con = 8, - }, - [PBIO_PORT_ID_3 - PBIO_PORT_ID_1] = { - .digi0 = 12, - .digi1 = 30, - .adc_val = 9, - .adc_con = 10, - }, - [PBIO_PORT_ID_4 - PBIO_PORT_ID_1] = { - .digi0 = 1, - .digi1 = 31, - .adc_val = 11, - .adc_con = 12, - }, -}; - -typedef enum { - NXT_LAMP_RED, - NXT_LAMP_GREEN, - NXT_LAMP_BLUE, - NXT_LAMP_OFF -} nxtcolor_color_state; - -typedef struct _nxtcolor_t { - bool ready; - bool fs_initialized; - bool waiting; - nxtcolor_color_state state; - nxtcolor_color_state lamp; - uint32_t calibration[3][4]; - uint16_t threshold[2]; - uint32_t raw_min; - uint32_t raw_max; - uint16_t crc; - uint32_t wait_start; - const nxtcolor_pininfo_t *pins; - FILE *f_digi0_val; - FILE *f_digi0_dir; - FILE *f_digi1_val; - FILE *f_digi1_dir; - bool digi1_dir; - FILE *f_adc_val; - FILE *f_adc_con; -} nxtcolor_t; - -nxtcolor_t nxtcolorsensors[4]; - -// Simplistic nonbusy wait. May be called only once per blocking operation. -pbio_error_t nxtcolor_wait(nxtcolor_t *nxtcolor, uint32_t ms) { - - uint32_t now = pbdrv_clock_get_ms(); - - // Wait for existing wait to complete - if (nxtcolor->waiting) { - if (now - nxtcolor->wait_start > ms) { - nxtcolor->waiting = false; - return PBIO_SUCCESS; - } - else { - return PBIO_ERROR_AGAIN; - } - } - // We are not waiting, so start a new wait - else { - nxtcolor->waiting = true; - nxtcolor->wait_start = now; - return PBIO_ERROR_AGAIN; - } -} - -static pbio_error_t nxtcolor_set_digi0(nxtcolor_t *nxtcolor, bool val) { - return sysfs_write_int(nxtcolor->f_digi0_val, val); -} - -static pbio_error_t nxtcolor_set_digi1(nxtcolor_t *nxtcolor, bool val) { - - pbio_error_t err; - - // First, ensure it is set as a digital out - if (nxtcolor->digi1_dir == IN) { - err = sysfs_write_str(nxtcolor->f_digi1_dir, "out"); - if (err != PBIO_SUCCESS) { - return err; - } - nxtcolor->digi1_dir = OUT; - } - // Set the requested state - return sysfs_write_int(nxtcolor->f_digi1_val, val); -} - -static pbio_error_t nxtcolor_get_digi1(nxtcolor_t *nxtcolor, bool *val) { - - pbio_error_t err; - - // First, ensure it is set as a digital in - if (nxtcolor->digi1_dir == OUT) { - err = sysfs_write_str(nxtcolor->f_digi1_dir, "in"); - if (err != PBIO_SUCCESS) { - return err; - } - nxtcolor->digi1_dir = IN; - } - // Get the state - int bit; - err = sysfs_read_int(nxtcolor->f_digi1_val, &bit); - if (err != PBIO_SUCCESS) { - return err; - } - *val = bit == 1; - return PBIO_SUCCESS; -} - -static pbio_error_t nxtcolor_get_adc(nxtcolor_t *nxtcolor, uint32_t *analog) { - - pbio_error_t err; - - // First, ensure it is set as an input - if (nxtcolor->digi1_dir == OUT) { - err = sysfs_write_str(nxtcolor->f_digi1_dir, "in"); - if (err != PBIO_SUCCESS) { - return err; - } - nxtcolor->digi1_dir = IN; - } - // Get the state - return sysfs_read_int(nxtcolor->f_adc_val, (int *)analog); -} - -static pbio_error_t nxtcolor_reset(nxtcolor_t *nxtcolor) -{ - pbio_error_t err; - - // Reset sequence init - err = nxtcolor_set_digi0(nxtcolor, 0); - if (err != PBIO_SUCCESS) { - return err; - } - err = nxtcolor_set_digi1(nxtcolor, 1); - if (err != PBIO_SUCCESS) { - return err; - } - - // Toggle digi0 several times - err = nxtcolor_set_digi0(nxtcolor, 1); - if (err != PBIO_SUCCESS) { - return err; - } - err = nxtcolor_set_digi0(nxtcolor, 0); - if (err != PBIO_SUCCESS) { - return err; - } - err = nxtcolor_set_digi0(nxtcolor, 1); - if (err != PBIO_SUCCESS) { - return err; - } - err = nxtcolor_set_digi0(nxtcolor, 0); - if (err != PBIO_SUCCESS) { - return err; - } - - return PBIO_SUCCESS; -} - -static pbio_error_t nxtcolor_read_byte(nxtcolor_t *nxtcolor, uint8_t *msg) -{ - pbio_error_t err; - *msg = 0; - - // Set data back to input - bool bit; - err = nxtcolor_get_digi1(nxtcolor, &bit); - if (err != PBIO_SUCCESS) { - return err; - } - - // Read 8 bits while toggling the "clock" - for (uint8_t i = 0; i < 8; i++) { - err = nxtcolor_set_digi0(nxtcolor, 1); - if (err != PBIO_SUCCESS) { - return err; - } - *msg = *msg >> 1; - err = nxtcolor_get_digi1(nxtcolor, &bit); - if (err != PBIO_SUCCESS) { - return err; - } - if (bit) { - *msg |= 0x80; - } - err = nxtcolor_set_digi0(nxtcolor, 0); - if (err != PBIO_SUCCESS) { - return err; - } - } - return PBIO_SUCCESS; -} - -static pbio_error_t nxtcolor_send_byte(nxtcolor_t *nxtcolor, uint8_t msg) -{ - pbio_error_t err; - - // Init both pins as low - err = nxtcolor_set_digi0(nxtcolor, 0); - if (err != PBIO_SUCCESS) { - return err; - } - err = nxtcolor_set_digi1(nxtcolor, 0); - if (err != PBIO_SUCCESS) { - return err; - } - - for (uint8_t i = 0; i < 8; i++) - { - // Set data pin - err = nxtcolor_set_digi1(nxtcolor, msg & 1); - if (err != PBIO_SUCCESS) { - return err; - } - msg = msg >> 1; - - // Set clock high - err = nxtcolor_set_digi0(nxtcolor, 1); - if (err != PBIO_SUCCESS) { - return err; - } - - // Set clock low - err = nxtcolor_set_digi0(nxtcolor, 0); - if (err != PBIO_SUCCESS) { - return err; - } - } - - return PBIO_SUCCESS; -} - -static pbio_error_t nxtcolor_init_fs(nxtcolor_t *nxtcolor, pbio_port_id_t port) { - - pbio_error_t err; - - // Get the pin info for this port - nxtcolor->pins = &pininfo[port-PBIO_PORT_ID_1]; - - // Open the sysfs files for this sensor - err = sysfs_open(&nxtcolor->f_digi0_val, "/sys/class/gpio/gpio%d/%s", nxtcolor->pins->digi0, "value", "w"); - if (err != PBIO_SUCCESS) { - return err; - } - err = sysfs_open(&nxtcolor->f_digi0_dir, "/sys/class/gpio/gpio%d/%s", nxtcolor->pins->digi0, "direction", "w"); - if (err != PBIO_SUCCESS) { - return err; - } - err = sysfs_open(&nxtcolor->f_digi1_val, "/sys/class/gpio/gpio%d/%s", nxtcolor->pins->digi1, "value", "r+"); - if (err != PBIO_SUCCESS) { - return err; - } - err = sysfs_open(&nxtcolor->f_digi1_dir, "/sys/class/gpio/gpio%d/%s", nxtcolor->pins->digi1, "direction", "w"); - if (err != PBIO_SUCCESS) { - return err; - } - err = sysfs_open(&nxtcolor->f_adc_con, "/sys/bus/iio/devices/iio:device0/in_voltage%d_raw%s", nxtcolor->pins->adc_con, "", "r"); - if (err != PBIO_SUCCESS) { - return err; - } - err = sysfs_open(&nxtcolor->f_adc_val, "/sys/bus/iio/devices/iio:device0/in_voltage%d_raw%s", nxtcolor->pins->adc_val, "", "r"); - if (err != PBIO_SUCCESS) { - return err; - } - - // Verify that the sensor is indeed attached - int32_t adc_con; - err = sysfs_read_int(nxtcolor->f_adc_con, &adc_con); - if (adc_con > 50) { - return PBIO_ERROR_NO_DEV; - } - - // Digi0 is always an output pin. Init as low - err = sysfs_write_str(nxtcolor->f_digi0_dir, "out"); - if (err != PBIO_SUCCESS) { - return err; - } - err = nxtcolor_set_digi0(nxtcolor, 0); - if (err != PBIO_SUCCESS) { - return err; - } - // Digi1 can be set as output, or read as digital, and analog. Init as low. - err = nxtcolor_set_digi1(nxtcolor, 0); - if (err != PBIO_SUCCESS) { - return err; - } - - return PBIO_SUCCESS; -} - -static pbio_error_t nxtcolor_init(nxtcolor_t *nxtcolor, pbio_port_id_t port) { - pbio_error_t err; - - // Init the file system - if (!nxtcolor->fs_initialized) { - err = nxtcolor_init_fs(nxtcolor, port); - if (err != PBIO_SUCCESS) { - return PBIO_ERROR_AGAIN; - } - nxtcolor->fs_initialized = true; - - // Reset the sensor - err = nxtcolor_reset(nxtcolor); - if (err != PBIO_SUCCESS) { - return err; - } - } - - // Wait 100 ms - err = nxtcolor_wait(nxtcolor, 100); - if (err != PBIO_SUCCESS) { - return err; - } - - // Set sensor to full color mode - err = nxtcolor_send_byte(nxtcolor, 13); - if (err != PBIO_SUCCESS) { - return err; - } - - // Read calibration data and crc bytes - uint8_t buf[sizeof(nxtcolor->calibration) + sizeof(nxtcolor->threshold) + sizeof(nxtcolor->crc)]; - for (uint8_t i = 0; i < sizeof(buf); i++) { - err = nxtcolor_read_byte(nxtcolor, &buf[i]); - if (err != PBIO_SUCCESS) { - return err; - } - } - - // Process first table - for (uint32_t row = 0; row < 3; row++) { - for (uint32_t col = 0; col < 4; col++) { - uint32_t val = 0; - uint32_t idx = row*4+col; - for (uint32_t b = 0; b < 4; b++) { - val += buf[idx*4+b] << 8*b; - } - nxtcolor->calibration[row][col] = val; - } - } - - // Process second table - uint32_t start = sizeof(buf) - sizeof(nxtcolor->crc) - sizeof(nxtcolor->threshold); - nxtcolor->threshold[0] = (buf[start+1] << 8) + buf[start+0]; - nxtcolor->threshold[1] = (buf[start+3] << 8) + buf[start+2]; - - // Other analog calibration values from NXT firmware / experiments - nxtcolor->raw_max = 750; - nxtcolor->raw_min = 50; - - // The sensor is now in the full-color-ambient state - nxtcolor->state = NXT_LAMP_OFF; - - return PBIO_SUCCESS; -} - -pbio_error_t nxtcolor_toggle_color(nxtcolor_t *nxtcolor) { - bool set = 0; - switch(nxtcolor->state) { - case NXT_LAMP_OFF: - nxtcolor->state = NXT_LAMP_RED; - set = 1; - break; - case NXT_LAMP_RED: - nxtcolor->state = NXT_LAMP_GREEN; - set = 0; - break; - case NXT_LAMP_GREEN: - nxtcolor->state = NXT_LAMP_BLUE; - set = 1; - break; - case NXT_LAMP_BLUE: - set = 0; - nxtcolor->state = NXT_LAMP_OFF; - break; - default: - return PBIO_ERROR_FAILED; - } - return nxtcolor_set_digi0(nxtcolor, set); -} - -pbio_error_t nxtcolor_set_light(nxtcolor_t *nxtcolor, nxtcolor_color_state color) { - pbio_error_t err; - - // Default unknown colors to no color - if (color > NXT_LAMP_OFF) { - color = NXT_LAMP_OFF; - } - - while (nxtcolor->state != color) { - err = nxtcolor_toggle_color(nxtcolor); - if (err != PBIO_SUCCESS) { - return err; - } - } - return PBIO_SUCCESS; -} - -pbio_error_t nxtcolor_get_values_at_mode(pbio_port_id_t port, uint8_t mode, int32_t *values) { - - pbio_error_t err; - - if (port < PBIO_PORT_ID_1 || port > PBIO_PORT_ID_4) { - return PBIO_ERROR_INVALID_ARG; - } - - nxtcolor_t *nxtcolor = &nxtcolorsensors[port-PBIO_PORT_ID_1]; - - // We don't have a formal "get" function since the higher level code - // does not know about the color sensor being a special case. So instead - // initialize the first time the sensor is called. - if (!nxtcolor->ready) { - err = nxtcolor_init(nxtcolor, port); - if (err != PBIO_SUCCESS) { - return err; - } - nxtcolor->ready = true; - } - - // In one of the lamp modes, just set the right color - if (mode > 0) { - switch(mode) { - case 1: - nxtcolor->lamp = NXT_LAMP_RED; - break; - case 2: - nxtcolor->lamp = NXT_LAMP_GREEN; - break; - case 3: - nxtcolor->lamp = NXT_LAMP_BLUE; - break; - default: - nxtcolor->lamp = NXT_LAMP_OFF; - break; - } - return nxtcolor_set_light(nxtcolor, nxtcolor->lamp); - } - - // In measure mode, cycle through the colors and calculate color id - uint32_t rgba[4]; - - // Read analog for each color - for (uint8_t i = 0; i < 4; i++) { - // Set the light - err = nxtcolor_set_light(nxtcolor, i); - if (err != PBIO_SUCCESS) { - return err; - } - err = nxtcolor_get_adc(nxtcolor, &rgba[i]); - if (err != PBIO_SUCCESS) { - return err; - } - } - - // Select calibration row based on ambient light - uint8_t row = 0; - if (rgba[3] < nxtcolor->threshold[1]) { - row = 2; - } - else if (rgba[3] < nxtcolor->threshold[0]) { - row = 1; - } - - // Adjust analog to percentage for each color - for (uint8_t i = 0; i < 3; i++) { - if (rgba[i] < rgba[3]){ - // If rgb is less than ambient, assume zero - values[i] = 0; - } - else { - // Otherwise, scale by calibration multiplier - values[i] = ( ( (rgba[i] - rgba[3])) * nxtcolor->calibration[row][i] ) / 38000; - - // On most sensors, red is about 10% too high on gray/white surfaces - if (i == 0) { - values[i] = values[i] * 100 / 110; - } - - values[i] = values[i] > 255 ? 255 : values[i]; - } - } - - // Clamp ambient between estimated max and min raw value - int32_t amb = max(nxtcolor->raw_min, min(rgba[3], nxtcolor->raw_max)); - - // Scale ambient to percentage - values[3] = ((amb-nxtcolor->raw_min)*100)/(nxtcolor->raw_max-nxtcolor->raw_min); - - // Set the light back to the configured lamp status - return nxtcolor_set_light(nxtcolor, nxtcolor->lamp); -} diff --git a/lib/ev3dev/src/ev3dev_stretch/sysfs.c b/lib/ev3dev/src/ev3dev_stretch/sysfs.c deleted file mode 100644 index b3fe9dd23..000000000 --- a/lib/ev3dev/src/ev3dev_stretch/sysfs.c +++ /dev/null @@ -1,146 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2018-2020 The Pybricks Authors - -#include -#include -#include -#include - -#include - -#include -#include - -#define MAX_PATH_LENGTH 60 -#define MAX_READ_LENGTH "60" - -// Get the ev3dev sensor number for a given port -pbio_error_t sysfs_get_number(pbio_port_id_t port, const char *rdir, int *sysfs_number) { - // Open lego-sensor directory in sysfs - DIR *d_sensor; - struct dirent *entry; - d_sensor = opendir(rdir); - if (!d_sensor) { - return PBIO_ERROR_NO_DEV; - } - // Find sensor number for given port - while ((entry = readdir(d_sensor))) { - // Ignore the . and .. folders - if (entry->d_name[0] != '.') { - // Open the address file to get the port number - char p_address[MAX_PATH_LENGTH]; -#pragma GCC diagnostic push -#if (__GNUC__ > 7) || (__GNUC__ == 7 && __GNUC_MINOR__ >= 1) -#pragma GCC diagnostic ignored "-Wformat-truncation" -#endif - snprintf(p_address, MAX_PATH_LENGTH, "%s/%s/address", rdir, entry->d_name); -#pragma GCC diagnostic pop - FILE *f_address = fopen(p_address, "r"); - if (f_address == NULL) { - return PBIO_ERROR_IO; - } - - char port_char; - if (fscanf(f_address, "ev3-ports:%*[a-z]%c", &port_char) < 1) { - return PBIO_ERROR_IO; - } - pbio_port_id_t port_found = port_char; - - if (fclose(f_address) != 0) { - return PBIO_ERROR_IO; - } - - // If the port matches the requested port, get where it was found. - if (port_found == port) { - sscanf(entry->d_name, "%*[a-z]%d", sysfs_number); - closedir(d_sensor); - return PBIO_SUCCESS; - } - } - } - // No sensor was found at the requested port - closedir(d_sensor); - return PBIO_ERROR_NO_DEV; -} - -// Open a sysfs attribute -pbio_error_t sysfs_open(FILE **file, const char *pathpat, int n, const char *attribute, const char *rw) { - char path[MAX_PATH_LENGTH]; - - snprintf(path, MAX_PATH_LENGTH, pathpat, n, attribute); - *file = fopen(path, rw); - if (!*file) { - return PBIO_ERROR_IO; - } - - setbuf(*file, NULL); - - return PBIO_SUCCESS; -} - -// Open a sensor sysfs attribute -pbio_error_t sysfs_open_sensor_attr(FILE **file, int n, const char *attribute, const char *rw) { - return sysfs_open(file, "/sys/class/lego-sensor/sensor%d/%s", n, attribute, rw); -} - -// Open a tacho-motor sysfs attribute -pbio_error_t sysfs_open_tacho_motor_attr(FILE **file, int n, const char *attribute, const char *rw) { - return sysfs_open(file, "/sys/class/tacho-motor/motor%d/%s", n, attribute, rw); -} - -// Open a dc-motor sysfs attribute -pbio_error_t sysfs_open_dc_motor_attr(FILE **file, int n, const char *attribute, const char *rw) { - return sysfs_open(file, "/sys/class/dc-motor/motor%d/%s", n, attribute, rw); -} - -// Read a string from a previously opened sysfs attribute -pbio_error_t sysfs_read_str(FILE *file, char *dest) { - if (fseek(file, 0, SEEK_SET) == -1) { - return PBIO_ERROR_IO; - } - - if (fscanf(file, "%" MAX_READ_LENGTH "s", dest) < 1) { - return PBIO_ERROR_IO; - } - - return PBIO_SUCCESS; -} - -// Write a string to a previously opened sysfs attribute -pbio_error_t sysfs_write_str(FILE *file, const char *str) { - if (fseek(file, 0, SEEK_SET) == -1) { - return PBIO_ERROR_IO; - } - - if (fprintf(file, "%s", str) != (int)strlen(str)) { - return PBIO_ERROR_IO; - } - - return PBIO_SUCCESS; -} - -// Read an int from a previously opened sysfs attribute -pbio_error_t sysfs_read_int(FILE *file, int *dest) { - if (fseek(file, 0, SEEK_SET) == -1) { - return PBIO_ERROR_IO; - } - - if (fscanf(file, "%d", dest) < 1) { - return PBIO_ERROR_IO; - } - - return PBIO_SUCCESS; -} - -// Write a number to a previously opened sysfs attribute -pbio_error_t sysfs_write_int(FILE *file, int val) { - if (fseek(file, 0, SEEK_SET) == -1) { - return PBIO_ERROR_IO; - } - - if (fprintf(file, "%d", val) <= 0) { - return PBIO_ERROR_IO; - } - - return PBIO_SUCCESS; -} diff --git a/lib/pbio/drv/counter/counter_ev3dev_stretch_iio.c b/lib/pbio/drv/counter/counter_ev3dev_stretch_iio.c deleted file mode 100644 index d7cfa8451..000000000 --- a/lib/pbio/drv/counter/counter_ev3dev_stretch_iio.c +++ /dev/null @@ -1,149 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2019-2020 The Pybricks Authors - -// ev3dev-stretch PRU/IIO Quadrature Encoder Counter driver -// -// This driver uses the PRU quadrature encoder found in ev3dev-stretch. - -#include - -#if PBDRV_CONFIG_COUNTER_EV3DEV_STRETCH_IIO - -#include -#include -#include - -#include - -#include -#include - -#include -#include - -#define DEBUG 0 -#if DEBUG -#define dbg_err(s) perror(s) -#else -#define dbg_err(s) -#endif - -struct _pbdrv_counter_dev_t { - FILE *count; - uint32_t time_us_last; - int32_t rotations_last; - int32_t millidegrees_last; -}; - -static pbdrv_counter_dev_t private_data[PBDRV_CONFIG_COUNTER_EV3DEV_STRETCH_IIO_NUM_DEV]; - -pbio_error_t pbdrv_counter_get_dev(uint8_t id, pbdrv_counter_dev_t **dev) { - if (id >= PBIO_ARRAY_SIZE(private_data)) { - return PBIO_ERROR_NO_DEV; - } - *dev = &private_data[id]; - return PBIO_SUCCESS; -} - -pbio_error_t pbdrv_counter_get_angle(pbdrv_counter_dev_t *dev, int32_t *rotations, int32_t *millidegrees) { - pbdrv_counter_dev_t *priv = dev; - - if (!priv->count) { - return PBIO_ERROR_NO_DEV; - } - - uint32_t time_now = pbdrv_clock_get_us(); - - // If values were recently read, return those again. - // This reduces unnecessary I/O operations. - if (time_now - priv->time_us_last < 2000) { - *rotations = priv->rotations_last; - *millidegrees = priv->millidegrees_last; - return PBIO_SUCCESS; - } - - if (fseek(priv->count, 0, SEEK_SET) == -1) { - return PBIO_ERROR_IO; - } - - int32_t count; - if (fscanf(priv->count, "%d", &count) == EOF) { - return PBIO_ERROR_IO; - } - - // ev3dev stretch provides 720 counts per rotation. - *rotations = count / 720; - *millidegrees = (count % 720) * 500; - - // Updated cached values - priv->time_us_last = time_now; - priv->rotations_last = *rotations; - priv->millidegrees_last = *millidegrees; - - return PBIO_SUCCESS; -} - -pbio_error_t pbdrv_counter_get_abs_angle(pbdrv_counter_dev_t *dev, int32_t *millidegrees) { - return PBIO_ERROR_NOT_SUPPORTED; -} - -void pbdrv_counter_init(void) { - char buf[256]; - struct udev *udev; - struct udev_enumerate *enumerate; - struct udev_list_entry *entry; - - udev = udev_new(); - if (!udev) { - dbg_err("Failed to get udev context"); - return; - } - - enumerate = udev_enumerate_new(udev); - if (!enumerate) { - dbg_err("Failed to get udev context"); - goto free_udev; - } - - if ((errno = udev_enumerate_add_match_subsystem(enumerate, "iio")) < 0) { - dbg_err("udev_enumerate_add_match_subsystem failed"); - goto free_enumerate; - } - - if ((errno = udev_enumerate_add_match_property(enumerate, "OF_NAME", "ev3-tacho-rpmsg")) < 0) { - dbg_err("udev_enumerate_add_match_property failed"); - goto free_enumerate; - } - - if ((errno = udev_enumerate_scan_devices(enumerate) < 0)) { - dbg_err("udev_enumerate_scan_devices failed"); - goto free_enumerate; - } - - entry = udev_enumerate_get_list_entry(enumerate); - if (!entry) { - dbg_err("udev_enumerate_get_list_entry failed"); - goto free_enumerate; - } - - - for (size_t i = 0; i < PBIO_ARRAY_SIZE(private_data); i++) { - pbdrv_counter_dev_t *priv = &private_data[i]; - - snprintf(buf, sizeof(buf), "%s/in_count%d_raw", udev_list_entry_get_name(entry), (int)i); - priv->count = fopen(buf, "r"); - if (!priv->count) { - dbg_err("failed to open count attribute"); - continue; - } - - setbuf(priv->count, NULL); - } - -free_enumerate: - udev_enumerate_unref(enumerate); -free_udev: - udev_unref(udev); -} - -#endif // PBDRV_CONFIG_COUNTER_EV3DEV_STRETCH_IIO diff --git a/lib/pbio/drv/legodev/legodev_ev3dev.c b/lib/pbio/drv/legodev/legodev_ev3dev.c deleted file mode 100644 index ccb915101..000000000 --- a/lib/pbio/drv/legodev/legodev_ev3dev.c +++ /dev/null @@ -1,211 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2019-2022 The Pybricks Authors - -#include - -#if PBDRV_CONFIG_LEGODEV_EV3DEV - -#include - -#include -#include -#include - -#include - -#include -#include -#include - -#include "legodev_ev3dev.h" -#include "legodev_spec.h" - -typedef struct { - const pbdrv_legodev_ev3dev_sensor_platform_data_t *pdata; - lego_sensor_t *ev3dev_sensor; - uint32_t mode_switch_time; - pbdrv_legodev_info_t info; - // The color sensor does not have a bin_data buffer, so buffer here. - int32_t color_sensor_rgba[4]; -} ev3dev_sensor_t; - -static ev3dev_sensor_t ev3dev_sensor_devs[PBDRV_CONFIG_LEGODEV_EV3DEV_NUM_SENSOR]; - -struct _pbdrv_legodev_dev_t { - bool is_motor; - union { - // Motor devices have only constant platform data. - const pbdrv_legodev_ev3dev_motor_platform_data_t *motor; - // Sensor devices have both a state and constant platform data. - ev3dev_sensor_t *sensor; - }; -}; - -static pbdrv_legodev_dev_t devs[PBDRV_CONFIG_LEGODEV_EV3DEV_NUM_MOTOR + PBDRV_CONFIG_LEGODEV_EV3DEV_NUM_SENSOR]; - -void pbdrv_legodev_init(void) { - for (uint8_t i = 0; i < PBDRV_CONFIG_LEGODEV_EV3DEV_NUM_MOTOR; i++) { - pbdrv_legodev_dev_t *legodev = &devs[i]; - legodev->is_motor = true; - legodev->motor = &pbdrv_legodev_ev3dev_motor_platform_data[i]; - } - - for (uint8_t i = 0; i < PBDRV_CONFIG_LEGODEV_EV3DEV_NUM_SENSOR; i++) { - pbdrv_legodev_dev_t *legodev = &devs[i + PBDRV_CONFIG_LEGODEV_EV3DEV_NUM_MOTOR]; - legodev->is_motor = false; - legodev->sensor = &ev3dev_sensor_devs[i]; - legodev->sensor->pdata = &pbdrv_legodev_ev3dev_sensor_platform_data[i]; - legodev->sensor->ev3dev_sensor = NULL; - legodev->sensor->mode_switch_time = pbdrv_clock_get_ms(); - } -} - -pbio_error_t pbdrv_legodev_get_motor_index(pbdrv_legodev_dev_t *legodev, uint8_t *index) { - if (!legodev->is_motor) { - return PBIO_ERROR_NO_DEV; - } - *index = legodev->motor->motor_driver_index; - return PBIO_SUCCESS; -} - -pbio_error_t pbdrv_legodev_get_angle(pbdrv_legodev_dev_t *legodev, pbio_angle_t *angle) { - if (!legodev->is_motor) { - return PBIO_ERROR_NOT_SUPPORTED; - } - pbdrv_counter_dev_t *counter; - pbio_error_t err = pbdrv_counter_get_dev(legodev->motor->motor_driver_index, &counter); - if (err != PBIO_SUCCESS) { - return err; - } - return pbdrv_counter_get_angle(counter, &angle->rotations, &angle->millidegrees); -} - -pbio_error_t pbdrv_legodev_get_abs_angle(pbdrv_legodev_dev_t *legodev, pbio_angle_t *angle) { - return PBIO_ERROR_NOT_SUPPORTED; -} - -pbio_error_t pbdrv_legodev_get_device(pbio_port_id_t port_id, pbdrv_legodev_type_id_t *type_id, pbdrv_legodev_dev_t **legodev) { - for (uint8_t i = 0; i < PBIO_ARRAY_SIZE(devs); i++) { - pbdrv_legodev_dev_t *candidate = &devs[i]; - - // Try to get a motor. - if (candidate->is_motor && candidate->motor->port_id == port_id) { - pbio_error_t err = ev3dev_motor_setup(port_id, *type_id != PBDRV_LEGODEV_TYPE_ID_ANY_DC_MOTOR); - if (err != PBIO_SUCCESS) { - return err; - } - *legodev = candidate; - return ev3dev_motor_get_id(port_id, type_id); - } - - // Try to get a sensor. - if (!candidate->is_motor && candidate->sensor->pdata->port_id == port_id) { - *legodev = candidate; - pbio_error_t err = lego_sensor_get(&candidate->sensor->ev3dev_sensor, port_id, *type_id); - if (err != PBIO_SUCCESS) { - return err; - } - - // For special sensor classes we are done. No need to read mode. - if (*type_id == PBDRV_LEGODEV_TYPE_ID_CUSTOM_I2C || - *type_id == PBDRV_LEGODEV_TYPE_ID_CUSTOM_UART || - *type_id == PBDRV_LEGODEV_TYPE_ID_NXT_COLOR_SENSOR) { - return PBIO_SUCCESS; - } - // Get mode - pbdrv_legodev_info_t *info = &candidate->sensor->info; - err = lego_sensor_get_mode(candidate->sensor->ev3dev_sensor, &info->mode); - if (err != PBIO_SUCCESS) { - return err; - } - // Get corresponding mode info - pbdrv_legodev_mode_info_t *mode_info = &candidate->sensor->info.mode_info[info->mode]; - return lego_sensor_get_info(candidate->sensor->ev3dev_sensor, &mode_info->num_values, (lego_sensor_data_type_t *)&mode_info->data_type); - } - } - return PBIO_ERROR_NO_DEV; -} - -bool pbdrv_legodev_needs_permanent_power(pbdrv_legodev_dev_t *legodev) { - return false; -} - -pbio_error_t pbdrv_legodev_get_info(pbdrv_legodev_dev_t *legodev, pbdrv_legodev_info_t **info) { - *info = &legodev->sensor->info; - return PBIO_SUCCESS; -} - -pbio_error_t pbdrv_legodev_is_ready(pbdrv_legodev_dev_t *legodev) { - if (legodev->is_motor) { - return PBIO_SUCCESS; - } - - if (!legodev->sensor->ev3dev_sensor) { - return PBIO_ERROR_NO_DEV; - } - - // Some device/mode pairs require time to discard stale data - uint32_t delay = pbdrv_legodev_spec_stale_data_delay(legodev->sensor->info.type_id, legodev->sensor->info.mode); - if (pbdrv_clock_get_ms() - legodev->sensor->mode_switch_time < delay) { - return PBIO_ERROR_AGAIN; - } - - return PBIO_SUCCESS; -} - -pbio_error_t pbdrv_legodev_set_mode(pbdrv_legodev_dev_t *legodev, uint8_t mode) { - if (legodev->is_motor) { - return PBIO_ERROR_NOT_SUPPORTED; - } - - if (!legodev->sensor->ev3dev_sensor) { - return PBIO_ERROR_NO_DEV; - } - - // Some device/mode pairs always require setting the mode. - pbdrv_legodev_info_t *info = &legodev->sensor->info; - bool mode_set_required = info->type_id == PBDRV_LEGODEV_TYPE_ID_EV3_ULTRASONIC_SENSOR && - mode >= PBDRV_LEGODEV_MODE_EV3_ULTRASONIC_SENSOR__SI_CM; - - // If mode already set and no change required, we are done. - if (info->mode == mode && !mode_set_required) { - return PBIO_SUCCESS; - } - - // Set new mode. - pbio_error_t err = lego_sensor_set_mode(legodev->sensor->ev3dev_sensor, mode); - if (err != PBIO_SUCCESS) { - return err; - } - info->mode = mode; - legodev->sensor->mode_switch_time = pbdrv_clock_get_ms(); - - // Get matching mode info. - pbdrv_legodev_mode_info_t *mode_info = &legodev->sensor->info.mode_info[info->mode]; - return lego_sensor_get_info(legodev->sensor->ev3dev_sensor, &mode_info->num_values, (lego_sensor_data_type_t *)&mode_info->data_type); -} - -pbio_error_t pbdrv_legodev_set_mode_with_data(pbdrv_legodev_dev_t *legodev, uint8_t mode, const void *data, uint8_t size) { - return PBIO_ERROR_NOT_SUPPORTED; -} - -pbio_error_t pbdrv_legodev_get_data(pbdrv_legodev_dev_t *legodev, uint8_t mode, void **data) { - if (legodev->is_motor) { - return PBIO_ERROR_NOT_SUPPORTED; - } - - if (!legodev->sensor->ev3dev_sensor) { - return PBIO_ERROR_NO_DEV; - } - - // The NXT Color Sensor has a custom routine not part of ev3dev. - if (legodev->sensor->info.type_id == PBDRV_LEGODEV_TYPE_ID_NXT_COLOR_SENSOR) { - *data = legodev->sensor->color_sensor_rgba; - return nxtcolor_get_values_at_mode(legodev->sensor->pdata->port_id, legodev->sensor->info.mode, legodev->sensor->color_sensor_rgba); - } - - // Get data from ev3dev. - return lego_sensor_get_bin_data(legodev->sensor->ev3dev_sensor, (uint8_t **)data); -} - -#endif // PBDRV_CONFIG_LEGODEV_EV3DEV diff --git a/lib/pbio/drv/legodev/legodev_ev3dev.h b/lib/pbio/drv/legodev/legodev_ev3dev.h deleted file mode 100644 index 20174a5a0..000000000 --- a/lib/pbio/drv/legodev/legodev_ev3dev.h +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2023 The Pybricks Authors - -#ifndef _INTERNAL_PBDRV_LEGODEV_EV3DEV_H_ -#define _INTERNAL_PBDRV_LEGODEV_EV3DEV_H_ - -#include - -#include - -#include -#include - -typedef struct { - pbio_port_id_t port_id; - uint8_t motor_driver_index; -} pbdrv_legodev_ev3dev_motor_platform_data_t; - -typedef struct { - pbio_port_id_t port_id; -} pbdrv_legodev_ev3dev_sensor_platform_data_t; - -#if PBDRV_CONFIG_LEGODEV_EV3DEV - -extern const pbdrv_legodev_ev3dev_motor_platform_data_t - pbdrv_legodev_ev3dev_motor_platform_data[PBDRV_CONFIG_LEGODEV_EV3DEV_NUM_MOTOR]; - -extern const pbdrv_legodev_ev3dev_sensor_platform_data_t - pbdrv_legodev_ev3dev_sensor_platform_data[PBDRV_CONFIG_LEGODEV_EV3DEV_NUM_SENSOR]; - -#endif // PBDRV_CONFIG_LEGODEV_EV3DEV - -#endif // _INTERNAL_PBDRV_LEGODEV_EV3DEV_H_ diff --git a/lib/pbio/drv/motor_driver/motor_driver_ev3dev_stretch.c b/lib/pbio/drv/motor_driver/motor_driver_ev3dev_stretch.c deleted file mode 100644 index 63b575ecf..000000000 --- a/lib/pbio/drv/motor_driver/motor_driver_ev3dev_stretch.c +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2022 The Pybricks Authors - -#include - -#if PBDRV_CONFIG_MOTOR_DRIVER_EV3DEV_STRETCH - -#include - -#include -#include - -#include - -struct _pbdrv_motor_driver_dev_t { - pbio_port_id_t port; -}; - -static pbdrv_motor_driver_dev_t motor_ports[PBDRV_CONFIG_MOTOR_DRIVER_NUM_DEV]; - -pbio_error_t pbdrv_motor_driver_get_dev(uint8_t id, pbdrv_motor_driver_dev_t **driver) { - if (id >= PBDRV_CONFIG_MOTOR_DRIVER_NUM_DEV) { - return PBIO_ERROR_INVALID_ARG; - } - - *driver = &motor_ports[id]; - - // if port has not been set, then driver has not been initialized - if ((*driver)->port == 0) { - return PBIO_ERROR_AGAIN; - } - - return PBIO_SUCCESS; -} - -pbio_error_t pbdrv_motor_driver_coast(pbdrv_motor_driver_dev_t *driver) { - return ev3dev_motor_stop(driver->port); -} - -pbio_error_t pbdrv_motor_driver_set_duty_cycle(pbdrv_motor_driver_dev_t *driver, int16_t duty_cycle) { - return ev3dev_motor_run(driver->port, 100 * duty_cycle / PBDRV_MOTOR_DRIVER_MAX_DUTY); -} - -void pbdrv_motor_driver_init(void) { - for (int i = 0; i < PBDRV_CONFIG_MOTOR_DRIVER_NUM_DEV; i++) { - motor_ports[i].port = PBDRV_CONFIG_FIRST_MOTOR_PORT + i; - } -} - -#endif // PBDRV_CONFIG_MOTOR_DRIVER_EV3DEV_STRETCH diff --git a/lib/pbio/platform/ev3dev_stretch/contiki-conf.h b/lib/pbio/platform/ev3dev_stretch/contiki-conf.h deleted file mode 100644 index 8c0ed1bf6..000000000 --- a/lib/pbio/platform/ev3dev_stretch/contiki-conf.h +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2018-2021 The Pybricks Authors - -#ifndef _PBIO_CONF_H_ -#define _PBIO_CONF_H_ - -#include - -#define CCIF -#define CLIF -#define AUTOSTART_ENABLE 1 - -// TODO: could use 64-bit time struct -typedef uint32_t clock_time_t; -#define CLOCK_CONF_SECOND 1000 - -#define clock_time pbdrv_clock_get_ms -#define clock_usecs pbdrv_clock_get_us - -#endif /* _PBIO_CONF_H_ */ diff --git a/lib/pbio/platform/ev3dev_stretch/pbdrvconfig.h b/lib/pbio/platform/ev3dev_stretch/pbdrvconfig.h deleted file mode 100644 index e018d8050..000000000 --- a/lib/pbio/platform/ev3dev_stretch/pbdrvconfig.h +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2018-2020,2022 The Pybricks Authors - -// platform-specific configuration for LEGO MINDSTORMS EV3 running ev3dev-stretch - -#define PBDRV_CONFIG_BATTERY (1) -#define PBDRV_CONFIG_BATTERY_LINUX_EV3 (1) - -#define PBDRV_CONFIG_BUTTON (1) -#define PBDRV_CONFIG_BUTTON_LINUX_EV3 (1) - -#define PBDRV_CONFIG_CLOCK (1) -#define PBDRV_CONFIG_CLOCK_LINUX (1) - -#define PBDRV_CONFIG_COUNTER (1) -#define PBDRV_CONFIG_COUNTER_NUM_DEV (4) -#define PBDRV_CONFIG_COUNTER_EV3DEV_STRETCH_IIO (1) -#define PBDRV_CONFIG_COUNTER_EV3DEV_STRETCH_IIO_NUM_DEV (4) - -#define PBDRV_CONFIG_IOPORT (0) -#define PBDRV_CONFIG_IOPORT_NUM_DEV (8) - -#define PBDRV_CONFIG_LEGODEV (1) -#define PBDRV_CONFIG_LEGODEV_MODE_INFO (1) -#define PBDRV_CONFIG_LEGODEV_EV3DEV (1) -#define PBDRV_CONFIG_LEGODEV_EV3DEV_NUM_MOTOR (4) -#define PBDRV_CONFIG_LEGODEV_EV3DEV_NUM_SENSOR (4) - -#define PBDRV_CONFIG_MOTOR_DRIVER (1) -#define PBDRV_CONFIG_MOTOR_DRIVER_NUM_DEV (4) -#define PBDRV_CONFIG_MOTOR_DRIVER_EV3DEV_STRETCH (1) - -#define PBDRV_CONFIG_HAS_PORT_A (1) -#define PBDRV_CONFIG_HAS_PORT_B (1) -#define PBDRV_CONFIG_HAS_PORT_C (1) -#define PBDRV_CONFIG_HAS_PORT_D (1) -#define PBDRV_CONFIG_HAS_PORT_1 (1) -#define PBDRV_CONFIG_HAS_PORT_2 (1) -#define PBDRV_CONFIG_HAS_PORT_3 (1) -#define PBDRV_CONFIG_HAS_PORT_4 (1) - -#define PBDRV_CONFIG_FIRST_MOTOR_PORT PBIO_PORT_ID_A -#define PBDRV_CONFIG_LAST_MOTOR_PORT PBIO_PORT_ID_D diff --git a/lib/pbio/platform/ev3dev_stretch/pbioconfig.h b/lib/pbio/platform/ev3dev_stretch/pbioconfig.h deleted file mode 100644 index eb7293b6b..000000000 --- a/lib/pbio/platform/ev3dev_stretch/pbioconfig.h +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2019-2023 The Pybricks Authors - -#define PBIO_CONFIG_BATTERY (1) -#define PBIO_CONFIG_DCMOTOR (1) -#define PBIO_CONFIG_DCMOTOR_NUM_DEV (4) -#define PBIO_CONFIG_DRIVEBASE_SPIKE (0) -#define PBIO_CONFIG_EV3_INPUT_DEVICE (1) -#define PBIO_CONFIG_IMU (0) -#define PBIO_CONFIG_LIGHT (1) -#define PBIO_CONFIG_LOGGER (1) -#define PBIO_CONFIG_SERIAL (1) -#define PBIO_CONFIG_MOTOR_PROCESS (1) -#define PBIO_CONFIG_SERVO (1) -#define PBIO_CONFIG_SERVO_NUM_DEV (4) -#define PBIO_CONFIG_SERVO_EV3_NXT (1) -#define PBIO_CONFIG_SERVO_PUP (0) -#define PBIO_CONFIG_SERVO_PUP_MOVE_HUB (0) -#define PBIO_CONFIG_TACHO (1) - -// On ev3dev, we can't keep up with a 5 ms loop. -#define PBIO_CONFIG_CONTROL_LOOP_TIME_MS (10) diff --git a/lib/pbio/platform/ev3dev_stretch/pbsysconfig.h b/lib/pbio/platform/ev3dev_stretch/pbsysconfig.h deleted file mode 100644 index 36c7f3e9a..000000000 --- a/lib/pbio/platform/ev3dev_stretch/pbsysconfig.h +++ /dev/null @@ -1,5 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2022 The Pybricks Authors - -#define PBSYS_CONFIG_BLUETOOTH (0) -#define PBSYS_CONFIG_STATUS_LIGHT (0) diff --git a/lib/pbio/platform/ev3dev_stretch/platform.c b/lib/pbio/platform/ev3dev_stretch/platform.c deleted file mode 100644 index c992ad890..000000000 --- a/lib/pbio/platform/ev3dev_stretch/platform.c +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2022 The Pybricks Authors - -#include "../../drv/legodev/legodev_ev3dev.h" - -const pbdrv_legodev_ev3dev_motor_platform_data_t pbdrv_legodev_ev3dev_motor_platform_data[PBDRV_CONFIG_LEGODEV_EV3DEV_NUM_MOTOR] = { - { - .port_id = PBIO_PORT_ID_A, - .motor_driver_index = 0, - }, - { - .port_id = PBIO_PORT_ID_B, - .motor_driver_index = 1, - }, - { - .port_id = PBIO_PORT_ID_C, - .motor_driver_index = 2, - }, - { - .port_id = PBIO_PORT_ID_D, - .motor_driver_index = 3, - }, -}; - -const pbdrv_legodev_ev3dev_sensor_platform_data_t pbdrv_legodev_ev3dev_sensor_platform_data[PBDRV_CONFIG_LEGODEV_EV3DEV_NUM_SENSOR] = { - { - .port_id = PBIO_PORT_ID_1, - }, - { - .port_id = PBIO_PORT_ID_2, - }, - { - .port_id = PBIO_PORT_ID_3, - }, - { - .port_id = PBIO_PORT_ID_4, - }, -}; diff --git a/lib/pbio/platform/ev3dev_stretch/status_light.c b/lib/pbio/platform/ev3dev_stretch/status_light.c deleted file mode 100644 index dec1b53d6..000000000 --- a/lib/pbio/platform/ev3dev_stretch/status_light.c +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2018-2020 The Pybricks Authors - -#include -#include -#include -#include - -#include -#include -#include - -#include "../src/light/color_light.h" - -#define NUM_LEDS 4 - -static FILE *brightness_sysfs_attr[NUM_LEDS]; -static pbio_color_light_t ev3dev_status_light_instance; -pbio_color_light_t *ev3dev_status_light = &ev3dev_status_light_instance; - -static void ev3dev_status_light_set_trigger(void) { - static bool is_set = false; - - // only need to set trigger once - if (is_set) { - return; - } - - static const char *const trigger_paths[NUM_LEDS] = { - "/sys/class/leds/led0:red:brick-status/trigger", - "/sys/class/leds/led1:red:brick-status/trigger", - "/sys/class/leds/led0:green:brick-status/trigger", - "/sys/class/leds/led1:green:brick-status/trigger" - }; - - for (int i = 0; i < NUM_LEDS; i++) { - FILE *trigger_sysfs_attr = fopen(trigger_paths[i], "w"); - if (!trigger_sysfs_attr) { - continue; - } - fprintf(trigger_sysfs_attr, "none"); - fclose(trigger_sysfs_attr); - } - - is_set = true; -} - -static pbio_error_t ev3dev_status_light_set_hsv(pbio_color_light_t *light, const pbio_color_hsv_t *hsv) { - ev3dev_status_light_set_trigger(); - - pbio_color_rgb_t rgb; - pbio_color_hsv_to_rgb(hsv, &rgb); - - // FIXME: need to adjust for chromacity to get better orange/yellow - - for (int i = 0; i < NUM_LEDS; i++) { - if (!brightness_sysfs_attr[i]) { - continue; - } - - int ret = fseek(brightness_sysfs_attr[i], 0, SEEK_SET); - if (ret == -1) { - return PBIO_ERROR_IO; - } - - ret = fprintf(brightness_sysfs_attr[i], "%d", i < 2 ? rgb.r : rgb.g); - if (ret < 0) { - return PBIO_ERROR_IO; - } - } - - return PBIO_SUCCESS; -} - -static const pbio_color_light_funcs_t ev3dev_status_light_funcs = { - .set_hsv = ev3dev_status_light_set_hsv, -}; - -void ev3dev_status_light_init(void) { - static const char *const brightness_paths[NUM_LEDS] = { - "/sys/class/leds/led0:red:brick-status/brightness", - "/sys/class/leds/led1:red:brick-status/brightness", - "/sys/class/leds/led0:green:brick-status/brightness", - "/sys/class/leds/led1:green:brick-status/brightness" - }; - - for (int i = 0; i < NUM_LEDS; i++) { - brightness_sysfs_attr[i] = fopen(brightness_paths[i], "w"); - if (!brightness_sysfs_attr[i]) { - continue; - } - setbuf(brightness_sysfs_attr[i], NULL); - } - - pbio_color_light_init(ev3dev_status_light, &ev3dev_status_light_funcs); -} diff --git a/pybricks/experimental/pb_module_experimental.c b/pybricks/experimental/pb_module_experimental.c index eec9aee45..0a77ca6fd 100644 --- a/pybricks/experimental/pb_module_experimental.c +++ b/pybricks/experimental/pb_module_experimental.c @@ -107,11 +107,6 @@ const mp_obj_module_t pb_module_experimental = { .globals = (mp_obj_dict_t *)&pb_module_experimental_globals, }; -#if PYBRICKS_RUNS_ON_EV3DEV -// ev3dev extends the C module in Python -MP_REGISTER_MODULE(MP_QSTR__experimental, pb_module_experimental); -#else MP_REGISTER_MODULE(MP_QSTR_pybricks_dot_experimental, pb_module_experimental); -#endif #endif // PYBRICKS_PY_EXPERIMENTAL diff --git a/pybricks/hubs/pb_type_ev3brick.c b/pybricks/hubs/pb_type_ev3brick.c index 53b0fff98..38f064eb3 100644 --- a/pybricks/hubs/pb_type_ev3brick.c +++ b/pybricks/hubs/pb_type_ev3brick.c @@ -11,20 +11,10 @@ #include #include -#if PYBRICKS_RUNS_ON_EV3DEV -#include "pb_ev3dev_types.h" - -// defined in pbio/platform/ev3dev_stretch/status_light.c -extern pbio_color_light_t *ev3dev_status_light; -#endif // PYBRICKS_RUNS_ON_EV3DEV - typedef struct _hubs_EV3Brick_obj_t { mp_obj_base_t base; mp_obj_t battery; mp_obj_t buttons; - mp_obj_t light; - mp_obj_t screen; - mp_obj_t speaker; mp_obj_t system; } hubs_EV3Brick_obj_t; @@ -56,12 +46,6 @@ static mp_obj_t hubs_EV3Brick_make_new(const mp_obj_type_t *type, size_t n_args, self->battery = MP_OBJ_FROM_PTR(&pb_module_battery); self->buttons = pb_type_Keypad_obj_new(pb_type_ev3brick_button_pressed); - #if PYBRICKS_RUNS_ON_EV3DEV - self->light = common_ColorLight_internal_obj_new(ev3dev_status_light); - mp_obj_t screen_args[] = { MP_ROM_QSTR(MP_QSTR__screen_) }; - self->screen = MP_OBJ_TYPE_GET_SLOT(&pb_type_ev3dev_Image, make_new)(&pb_type_ev3dev_Image, 1, 0, screen_args); - self->speaker = MP_OBJ_TYPE_GET_SLOT(&pb_type_ev3dev_Speaker, make_new)(&pb_type_ev3dev_Speaker, 0, 0, NULL); - #endif // PYBRICKS_RUNS_ON_EV3DEV self->system = MP_OBJ_FROM_PTR(&pb_type_System); return MP_OBJ_FROM_PTR(self); @@ -70,11 +54,6 @@ static mp_obj_t hubs_EV3Brick_make_new(const mp_obj_type_t *type, size_t n_args, static const pb_attr_dict_entry_t hubs_EV3Brick_attr_dict[] = { PB_DEFINE_CONST_ATTR_RO(MP_QSTR_battery, hubs_EV3Brick_obj_t, battery), PB_DEFINE_CONST_ATTR_RO(MP_QSTR_buttons, hubs_EV3Brick_obj_t, buttons), - #if PYBRICKS_RUNS_ON_EV3DEV - PB_DEFINE_CONST_ATTR_RO(MP_QSTR_light, hubs_EV3Brick_obj_t, light), - PB_DEFINE_CONST_ATTR_RO(MP_QSTR_screen, hubs_EV3Brick_obj_t, screen), - PB_DEFINE_CONST_ATTR_RO(MP_QSTR_speaker, hubs_EV3Brick_obj_t, speaker), - #endif // PYBRICKS_RUNS_ON_EV3DEV PB_DEFINE_CONST_ATTR_RO(MP_QSTR_system, hubs_EV3Brick_obj_t, system), PB_ATTR_DICT_SENTINEL }; diff --git a/pybricks/iodevices/pb_type_iodevices_ev3devsensor.c b/pybricks/iodevices/pb_type_iodevices_ev3devsensor.c deleted file mode 100644 index 37c1c5a98..000000000 --- a/pybricks/iodevices/pb_type_iodevices_ev3devsensor.c +++ /dev/null @@ -1,116 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2018-2023 The Pybricks Authors - -#include "py/mpconfig.h" - -#if PYBRICKS_PY_IODEVICES && PYBRICKS_PY_EV3DEVICES - -#include - -#include - -#include -#include - -#include -#include -#include -#include - -#include - -// Class structure for Ev3devSensor -typedef struct _iodevices_Ev3devSensor_obj_t { - pb_type_device_obj_base_t device_base; - mp_obj_t sensor_index; - mp_obj_t port_index; -} iodevices_Ev3devSensor_obj_t; - -// pybricks.iodevices.Ev3devSensor.__init__ -static mp_obj_t iodevices_Ev3devSensor_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - PB_PARSE_ARGS_CLASS(n_args, n_kw, args, - PB_ARG_REQUIRED(port)); - - iodevices_Ev3devSensor_obj_t *self = mp_obj_malloc(iodevices_Ev3devSensor_obj_t, type); - pb_type_device_init_class(&self->device_base, port_in, PBDRV_LEGODEV_TYPE_ID_EV3DEV_LEGO_SENSOR); - - // Get the sysfs index. This is not currently exposed through pb_device, - // so read it again by searching through the sysfs tree. - int32_t sensor_index, port_index; - pbio_port_id_t port = pb_type_enum_get_value(port_in, &pb_enum_type_Port); - pb_assert(sysfs_get_number(port, "/sys/class/lego-sensor", &sensor_index)); - pb_assert(sysfs_get_number(port, "/sys/class/lego-port", &port_index)); - self->sensor_index = mp_obj_new_int(sensor_index); - self->port_index = mp_obj_new_int(port_index); - - return MP_OBJ_FROM_PTR(self); -} - -// pybricks.iodevices.Ev3devSensor.read -static mp_obj_t iodevices_Ev3devSensor_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args, - iodevices_Ev3devSensor_obj_t, self, - PB_ARG_REQUIRED(mode)); - - pbdrv_legodev_info_t *info; - pb_assert(pbdrv_legodev_get_info(self->device_base.legodev, &info)); - - uint8_t mode = 0; - for (mode = 0; mode < info->num_modes; mode++) { - if (!strncmp(info->mode_info[mode].name, mp_obj_str_get_str(mode_in), LUMP_MAX_NAME_SIZE)) { - break; - } - } - if (mode == info->num_modes) { - pb_assert(PBIO_ERROR_INVALID_ARG); - } - - void *data = pb_type_device_get_data_blocking(MP_OBJ_FROM_PTR(self), mode); - mp_obj_t values[PBDRV_LEGODEV_MAX_DATA_SIZE]; - - for (uint8_t i = 0; i < info->mode_info[mode].num_values; i++) { - switch (info->mode_info[mode].data_type) { - case PBDRV_LEGODEV_DATA_TYPE_INT8: - values[i] = mp_obj_new_int(((int8_t *)data)[i]); - break; - case PBDRV_LEGODEV_DATA_TYPE_INT16: - values[i] = mp_obj_new_int(((int16_t *)data)[i]); - break; - case PBDRV_LEGODEV_DATA_TYPE_INT32: - values[i] = mp_obj_new_int(((int32_t *)data)[i]); - break; - #if MICROPY_PY_BUILTINS_FLOAT - case PBDRV_LEGODEV_DATA_TYPE_FLOAT: - values[i] = mp_obj_new_float_from_f(((float *)data)[i]); - break; - #endif - default: - pb_assert(PBIO_ERROR_IO); - } - } - return mp_obj_new_tuple(info->mode_info[mode].num_values, values); -} -MP_DEFINE_CONST_FUN_OBJ_KW(iodevices_Ev3devSensor_read_obj, 1, iodevices_Ev3devSensor_read); - -static const pb_attr_dict_entry_t iodevices_Ev3devSensor_attr_dict[] = { - PB_DEFINE_CONST_ATTR_RO(MP_QSTR_sensor_index, iodevices_Ev3devSensor_obj_t, sensor_index), - PB_DEFINE_CONST_ATTR_RO(MP_QSTR_port_index, iodevices_Ev3devSensor_obj_t, port_index), - PB_ATTR_DICT_SENTINEL -}; - -// dir(pybricks.iodevices.Ev3devSensor) -static const mp_rom_map_elem_t iodevices_Ev3devSensor_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&iodevices_Ev3devSensor_read_obj) }, -}; -static MP_DEFINE_CONST_DICT(iodevices_Ev3devSensor_locals_dict, iodevices_Ev3devSensor_locals_dict_table); - -// type(pybricks.iodevices.Ev3devSensor) -MP_DEFINE_CONST_OBJ_TYPE(pb_type_iodevices_Ev3devSensor, - MP_QSTR_Ev3devSensor, - MP_TYPE_FLAG_NONE, - make_new, iodevices_Ev3devSensor_make_new, - attr, pb_attribute_handler, - protocol, iodevices_Ev3devSensor_attr_dict, - locals_dict, &iodevices_Ev3devSensor_locals_dict); - -#endif // PYBRICKS_PY_IODEVICES && PYBRICKS_PY_EV3DEVICES diff --git a/pybricks/nxtdevices/pb_module_nxtdevices.c b/pybricks/nxtdevices/pb_module_nxtdevices.c index 382b67a59..c29a3d332 100644 --- a/pybricks/nxtdevices/pb_module_nxtdevices.c +++ b/pybricks/nxtdevices/pb_module_nxtdevices.c @@ -30,11 +30,6 @@ const mp_obj_module_t pb_module_nxtdevices = { .globals = (mp_obj_dict_t *)&pb_module_nxtdevices_globals, }; -#if PYBRICKS_RUNS_ON_EV3DEV -// ev3dev extends the C module in Python -MP_REGISTER_MODULE(MP_QSTR__nxtdevices, pb_module_nxtdevices); -#else MP_REGISTER_MODULE(MP_QSTR_pybricks_dot_nxtdevices, pb_module_nxtdevices); -#endif #endif // PYBRICKS_PY_NXTDEVICES diff --git a/pybricks/pybricks.c b/pybricks/pybricks.c index b1b8efd2f..8caa339b8 100644 --- a/pybricks/pybricks.c +++ b/pybricks/pybricks.c @@ -61,12 +61,7 @@ const mp_obj_module_t pb_package_pybricks = { .globals = (mp_obj_dict_t *)&pb_package_pybricks_globals, }; -#if PYBRICKS_RUNS_ON_EV3DEV -// ev3dev extends the C module in Python -MP_REGISTER_MODULE(MP_QSTR_pybricks_c, pb_package_pybricks); -#else MP_REGISTER_MODULE(MP_QSTR_pybricks, pb_package_pybricks); -#endif #if PYBRICKS_OPT_COMPILER /** diff --git a/pybricks/tools/pb_module_tools.c b/pybricks/tools/pb_module_tools.c index 7e62756b4..8126932bc 100644 --- a/pybricks/tools/pb_module_tools.c +++ b/pybricks/tools/pb_module_tools.c @@ -382,12 +382,7 @@ const mp_obj_module_t pb_module_tools = { .globals = (mp_obj_dict_t *)&pb_module_tools_globals, }; -#if PYBRICKS_RUNS_ON_EV3DEV -// ev3dev extends the C module in Python -MP_REGISTER_MODULE(MP_QSTR__tools, pb_module_tools); -#else MP_REGISTER_MODULE(MP_QSTR_pybricks_dot_tools, pb_module_tools); -#endif // backwards compatibility for pybricks.geometry #if MICROPY_PY_BUILTINS_FLOAT diff --git a/pybricks/util_pb/pb_serial.h b/pybricks/util_pb/pb_serial.h deleted file mode 100644 index 50d127f78..000000000 --- a/pybricks/util_pb/pb_serial.h +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2018-2020 The Pybricks Authors - -#include -#include - -#include -#include - -typedef struct _pb_serial_t pb_serial_t; - -pbio_error_t pb_serial_get(pb_serial_t **_ser, pbio_port_id_t port, int baudrate); - -pbio_error_t pb_serial_write(pb_serial_t *ser, const void *buf, size_t count); - -pbio_error_t pb_serial_in_waiting(pb_serial_t *ser, size_t *waiting); - -pbio_error_t pb_serial_read(pb_serial_t *ser, uint8_t *buf, size_t count, size_t *received); - -pbio_error_t pb_serial_clear(pb_serial_t *ser); diff --git a/pybricks/util_pb/pb_serial_ev3dev.c b/pybricks/util_pb/pb_serial_ev3dev.c deleted file mode 100644 index cb9f8ca01..000000000 --- a/pybricks/util_pb/pb_serial_ev3dev.c +++ /dev/null @@ -1,208 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2018-2020 The Pybricks Authors - -// Portions of this file (termios settings) adapted from MicroPython, modtermios.c -// Copyright (c) 2014-2015 Paul Sokolovsky - -#include "py/mpconfig.h" - -#if PYBRICKS_RUNS_ON_EV3DEV - -#include -#include -#include -#include -#include - -#include -#include - -#include - -static const char *const TTY_PATH[] = { - "/dev/tty_ev3-ports:in1", - "/dev/tty_ev3-ports:in2", - "/dev/tty_ev3-ports:in3", - "/dev/tty_ev3-ports:in4", -}; - -struct _pb_serial_t { - int file; - int timeout; -}; - -pb_serial_t pb_serials[PBIO_ARRAY_SIZE(TTY_PATH)]; - -static pbio_error_t pb_serial_open(pb_serial_t *ser, const char *path) { - - ser->file = open(path, O_RDWR | O_NOCTTY | O_NONBLOCK); - if (ser->file == -1) { - return PBIO_ERROR_IO; - } - - return PBIO_SUCCESS; -} - -static pbio_error_t pb_serial_config(pb_serial_t *ser, int baudrate) { - - // Convert to termios baudrate - speed_t speed; - switch (baudrate) { - case 50: - speed = B50; - break; - case 75: - speed = B75; - break; - case 110: - speed = B110; - break; - case 134: - speed = B134; - break; - case 150: - speed = B150; - break; - case 200: - speed = B200; - break; - case 300: - speed = B300; - break; - case 600: - speed = B600; - break; - case 1200: - speed = B1200; - break; - case 1800: - speed = B1800; - break; - case 2400: - speed = B2400; - break; - case 4800: - speed = B4800; - break; - case 9600: - speed = B9600; - break; - case 19200: - speed = B19200; - break; - case 38400: - speed = B38400; - break; - case 57600: - speed = B57600; - break; - case 115200: - speed = B115200; - break; - case 230400: - speed = B230400; - break; - case 460800: - speed = B460800; - break; - case 500000: - speed = B500000; - break; - case 576000: - speed = B576000; - break; - default: - return PBIO_ERROR_INVALID_ARG; - } - - // Get termios attributes - struct termios term; - if (tcgetattr(ser->file, &term) != 0) { - return PBIO_ERROR_IO; - } - - // Set termios attributes - term.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); - term.c_oflag = 0; - term.c_cflag = (term.c_cflag & ~(CSIZE | PARENB)) | CS8; - term.c_lflag = 0; - term.c_cc[VMIN] = 1; - term.c_cc[VTIME] = 0; - - if (cfsetspeed(&term, speed) != 0) { - return PBIO_ERROR_IO; - } - - // Write attributes - if (tcsetattr(ser->file, TCSAFLUSH, &term) != 0) { - return PBIO_ERROR_IO; - } - - return PBIO_SUCCESS; -} - - -pbio_error_t pb_serial_get(pb_serial_t **_ser, pbio_port_id_t port, int baudrate) { - - if (port < PBIO_PORT_ID_1 || port > PBIO_PORT_ID_4) { - return PBIO_ERROR_INVALID_ARG; - } - - // Get device pointer - pbio_error_t err; - pb_serial_t *ser = &pb_serials[port - PBIO_PORT_ID_1]; - - // Open pb_serial port - err = pb_serial_open(ser, TTY_PATH[port - PBIO_PORT_ID_1]); - if (err != PBIO_SUCCESS) { - return err; - } - - // Config pb_serial port - err = pb_serial_config(ser, baudrate); - if (err != PBIO_SUCCESS) { - return err; - } - - // Return pointer to device - *_ser = ser; - - return PBIO_SUCCESS; -} - -pbio_error_t pb_serial_write(pb_serial_t *ser, const void *buf, size_t count) { - if (write(ser->file, buf, count) != (int)count) { - return PBIO_ERROR_IO; - } - return PBIO_SUCCESS; -} - -pbio_error_t pb_serial_in_waiting(pb_serial_t *ser, size_t *waiting) { - if (ioctl(ser->file, FIONREAD, waiting) == -1) { - return PBIO_ERROR_IO; - } - return PBIO_SUCCESS; -} - -pbio_error_t pb_serial_read(pb_serial_t *ser, uint8_t *buf, size_t count, size_t *received) { - int ret = read(ser->file, buf, count); - if (ret < 0) { - if (errno == EAGAIN) { - *received = 0; - return PBIO_SUCCESS; - } else { - return PBIO_ERROR_IO; - } - } - *received = ret; - return PBIO_SUCCESS; -} - -pbio_error_t pb_serial_clear(pb_serial_t *ser) { - if (tcflush(ser->file, TCIOFLUSH) != 0) { - return PBIO_ERROR_IO; - } - return PBIO_SUCCESS; -} - -#endif // PYBRICKS_RUNS_ON_EV3DEV diff --git a/test-ev3dev.sh b/test-ev3dev.sh deleted file mode 100755 index a4ba79199..000000000 --- a/test-ev3dev.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# -# Runs tests on ev3dev port. -# -# Use `--list-test` to list tests or `--include ` to run single tests. -# - -set -e - -SCRIPT_DIR=$(dirname "$0") -BRICK_DIR="$SCRIPT_DIR/bricks/ev3dev" -MP_TEST_DIR="$SCRIPT_DIR/micropython/tests" -PB_TEST_DIR=$(readlink -f "$SCRIPT_DIR/tests") -BUILD_DIR=$(readlink -f "$BRICK_DIR/build-test") - -make -s -j $(nproc --all) -C "$BRICK_DIR" build-test/pybricks-micropython build-test/libgrx-3.0-vdriver-test.so CROSS_COMPILE= DEBUG=1 COPT=-O0 BUILD=build-test - -export PYBRICKS_MICROPYTHON="$BUILD_DIR/pybricks-micropython" -export MICROPY_MICROPYTHON="$PB_TEST_DIR/ev3dev/test-wrapper.sh" -export GRX_PLUGIN_PATH="$BUILD_DIR" -export GRX_DRIVER=test - -cd "$MP_TEST_DIR" -./run-tests.py --test-dirs $(find "$PB_TEST_DIR/ev3dev" -type d) "$@" || ./run-tests.py --print-failures diff --git a/tests/ev3dev/.gitignore b/tests/ev3dev/.gitignore deleted file mode 100644 index 1f2c0e2d7..000000000 --- a/tests/ev3dev/.gitignore +++ /dev/null @@ -1 +0,0 @@ -libgrx-3.0-vdriver-test.so diff --git a/tests/ev3dev/Makefile b/tests/ev3dev/Makefile deleted file mode 100644 index 57085626e..000000000 --- a/tests/ev3dev/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: MIT -# Copyright (c) 2019-2020 The Pybricks Authors - -CFLAGS += $(shell pkg-config --cflags grx-3.0) -LDFLAGS += $(shell pkg-config --libs grx-3.0) - -CFLAGS += -fPIC -LDFLAGS += -shared - -libgrx-3.0-vdriver-test.so: grx-plugin.o - $(LD) $(LDFLAGS) -o $@ $< - -grx-plugin.o: Makefile diff --git a/tests/ev3dev/brick/battery.py b/tests/ev3dev/brick/battery.py deleted file mode 100644 index 31cf0e7d9..000000000 --- a/tests/ev3dev/brick/battery.py +++ /dev/null @@ -1,11 +0,0 @@ -from pybricks.hubs import EV3Brick - -ev3 = EV3Brick() - -print(ev3.battery.voltage()) # 7400 -print(ev3.battery.current()) # 180 -print(ev3.battery.type()) # Alkaline -try: - ev3.battery.temperature() -except OSError as ex: - print(ex.errno) # 95: EOPNOTSUPP diff --git a/tests/ev3dev/brick/battery.py.exp b/tests/ev3dev/brick/battery.py.exp deleted file mode 100644 index 5a49046be..000000000 --- a/tests/ev3dev/brick/battery.py.exp +++ /dev/null @@ -1,4 +0,0 @@ -7400 -180 -Alkaline -95 diff --git a/tests/ev3dev/brick/screen.py b/tests/ev3dev/brick/screen.py deleted file mode 100644 index 6c7eff098..000000000 --- a/tests/ev3dev/brick/screen.py +++ /dev/null @@ -1,137 +0,0 @@ -from pybricks.hubs import EV3Brick -from pybricks.parameters import Color -from pybricks.media.ev3dev import Font - -ev3 = EV3Brick() - -# Test contants - -print(ev3.screen.width) -print(ev3.screen.height) - - -# Test clear() - -ev3.screen.clear() - - -# Test draw_pixel() - -# two required arguments -ev3.screen.draw_pixel(0, 0) -ev3.screen.draw_pixel(x=0, y=0) -try: - ev3.screen.draw_pixel(0) -except TypeError: - pass - -# 3rd argument is kwarg -ev3.screen.draw_pixel(0, 0, Color.BLACK) -ev3.screen.draw_pixel(0, 0, color=Color.BLACK) - - -# Test draw_line() - -# four required arguments -ev3.screen.draw_line(0, 0, 0, 0) -ev3.screen.draw_line(x1=0, y1=0, x2=0, y2=0) -try: - ev3.screen.draw_line(0, 0, 0) -except TypeError: - pass - -# 5th argument is kwarg -ev3.screen.draw_line(0, 0, 0, 0, 1) -ev3.screen.draw_line(0, 0, 0, 0, width=1) - -# 6th argument is kwarg -ev3.screen.draw_line(0, 0, 0, 0, 1, Color.BLACK) -ev3.screen.draw_line(0, 0, 0, 0, color=Color.BLACK) - - -# Test draw_box() - -# four required arguments -ev3.screen.draw_box(0, 0, 0, 0) -ev3.screen.draw_box(x1=0, y1=0, x2=0, y2=0) -try: - ev3.screen.draw_box(0, 0, 0) -except TypeError: - pass - -# 5th argument is kwarg -ev3.screen.draw_box(0, 0, 0, 0, 0) -ev3.screen.draw_box(0, 0, 0, 0, r=0) - -# 6th argument is kwarg -ev3.screen.draw_box(0, 0, 0, 0, 0, False) -ev3.screen.draw_box(0, 0, 0, 0, fill=False) - -# 6th argument is kwarg -ev3.screen.draw_box(0, 0, 0, 0, 0, False, Color.BLACK) -ev3.screen.draw_box(0, 0, 0, 0, color=Color.BLACK) - - -# Test draw_circle() - -# three required arguments -ev3.screen.draw_circle(0, 0, 0) -ev3.screen.draw_circle(x=0, y=0, r=0) -try: - ev3.screen.draw_circle(0, 0) -except TypeError: - pass - -# 4th argument is kwarg -ev3.screen.draw_circle(0, 0, 0, False) -ev3.screen.draw_circle(0, 0, 0, fill=False) - -# 5th argument is kwarg -ev3.screen.draw_circle(0, 0, 0, False, Color.BLACK) -ev3.screen.draw_circle(0, 0, 0, color=Color.BLACK) - - -# Test draw_text() - -# three required arguments -ev3.screen.draw_text(0, 0, "") -ev3.screen.draw_text(x=0, y=0, text="") -try: - ev3.screen.draw_text(0, 0) -except TypeError: - pass - -# 4th argument is kwarg -ev3.screen.draw_text(0, 0, "", Color.BLACK) -ev3.screen.draw_text(0, 0, "", text_color=Color.BLACK) - -# 5th argument is kwarg -ev3.screen.draw_text(0, 0, "", Color.BLACK, Color.WHITE) -ev3.screen.draw_text(0, 0, "", background_color=Color.WHITE) - - -# Test set_font() - -# one required argument -ev3.screen.set_font(Font.DEFAULT) -try: - ev3.screen.set_font() -except TypeError: - pass - - -# Test print() - -# no required arguments -ev3.screen.print() - -# positional args take any object type -ev3.screen.print("", 0, False, ev3.screen, {}, []) - -# keyword-only arg end -ev3.screen.print(end="\n") -ev3.screen.print("", end="\n") - -# keyword-only arg sep -ev3.screen.print(sep=" ") -ev3.screen.print("", sep=" ") diff --git a/tests/ev3dev/brick/screen.py.exp b/tests/ev3dev/brick/screen.py.exp deleted file mode 100644 index 49445e139..000000000 --- a/tests/ev3dev/brick/screen.py.exp +++ /dev/null @@ -1,2 +0,0 @@ -178 -128 diff --git a/tests/ev3dev/brick/speaker.py b/tests/ev3dev/brick/speaker.py deleted file mode 100644 index 9fe039ed7..000000000 --- a/tests/ev3dev/brick/speaker.py +++ /dev/null @@ -1,175 +0,0 @@ -from pybricks.hubs import EV3Brick -from pybricks.media.ev3dev import SoundFile - -ev3 = EV3Brick() - - -# beep method - -# beep with no args is OK -ev3.speaker.beep() - -# beep with 1 arg is OK -ev3.speaker.beep(500) - -# beep with 2 args is OK -ev3.speaker.beep(500, 500) - -# beep with keyword args is OK -ev3.speaker.beep(frequency=500, duration=500) - -try: - # beep with 3 args is not OK - ev3.speaker.beep(500, 500, 500) -except TypeError as ex: - print(ex) - -# floats are converted to int -ev3.speaker.beep(500.1, 500.1) - - -# beep play_notes method - -# Requires 1 arg -try: - ev3.speaker.play_notes() -except TypeError as ex: - print(ex) - -# one arg is OK -ev3.speaker.play_notes([]) - -# two args is OK -ev3.speaker.play_notes([], 120) - -# keyword args are OK -ev3.speaker.play_notes(notes=[], tempo=120) - -# String doesn't work because it iterates each character -try: - ev3.speaker.play_notes("C4/4") -except ValueError as ex: - print(ex) - -# First character must be A-G or R -try: - ev3.speaker.play_notes(["X"]) -except ValueError as ex: - print(ex) - -# Second character must be 2-8 -try: - ev3.speaker.play_notes(["C1"]) -except ValueError as ex: - print(ex) - -# Certain notes can't have sharp or flat -try: - ev3.speaker.play_notes(["Cb"]) -except ValueError as ex: - print(ex) - -# '/' delimiter is required -try: - ev3.speaker.play_notes(["C#4"]) -except ValueError as ex: - print(ex) - -# fraction is required -try: - ev3.speaker.play_notes(["Db4/"]) -except ValueError as ex: - print(ex) - - -def notes(): - yield "E4/4" - raise RuntimeError("notes iter error") - - -# exception from iterator propagates -try: - ev3.speaker.play_notes(notes()) -except RuntimeError as ex: - print(ex) - - -# play_file method - -# Requires one argument -try: - ev3.speaker.play_file() -except TypeError as ex: - print(ex) - -# one argument OK -ev3.speaker.play_file(SoundFile.HELLO) - -# keyword argument OK -ev3.speaker.play_file(file=SoundFile.HELLO) - -# file not found gives RuntimeError -try: - ev3.speaker.play_file("bad") -except RuntimeError as ex: - print(ex) - - -# say method - -# Requires one argument -try: - ev3.speaker.say() -except TypeError as ex: - print(ex) - -# one argument OK -ev3.speaker.say("hi") - -# keyword argument OK -ev3.speaker.say(text="hi") - - -# set_volume method - -# Requires one argument -try: - ev3.speaker.set_volume() -except TypeError as ex: - print(ex) - -# one argument OK -ev3.speaker.set_volume(0) - -# two arguments OK -ev3.speaker.set_volume(0, "Beep") - -# keyword argument OK -ev3.speaker.set_volume(volume=0, which="Beep") - -# only certain values allowed for which= -try: - ev3.speaker.set_volume(0, "bad") -except ValueError as ex: - print(ex) - - -# set_speech_options method - -# No required arguments (although this is noop) -ev3.speaker.set_speech_options() - -# one argument is OK -ev3.speaker.set_speech_options("en") - -# two options are OK -ev3.speaker.set_speech_options("en", "f1") - -# three options are OK -ev3.speaker.set_speech_options("en", "f1", 100) - -# four options are OK -ev3.speaker.set_speech_options("en", "f1", 100, 50) - -# keyword args are OK -ev3.speaker.set_speech_options(language="en", voice="f1", speed=100, pitch=50) diff --git a/tests/ev3dev/brick/speaker.py.exp b/tests/ev3dev/brick/speaker.py.exp deleted file mode 100644 index 5c3cd9330..000000000 --- a/tests/ev3dev/brick/speaker.py.exp +++ /dev/null @@ -1,15 +0,0 @@ -extra positional arguments given -'notes' argument required -Missing octave number 2-8 -Missing note name A-G or R -Missing octave number 2-8 -'Cb' is not allowed -Missing '/' -Missing fractional value 1, 2, 4, 8, etc. -notes iter error -'file' argument required -Playing file failed: bad: No such file or directory - -'text' argument required -'volume' argument required -which must be one of '_all_', 'Beep', 'PCM' diff --git a/tests/ev3dev/experimental/thread_tools.py b/tests/ev3dev/experimental/thread_tools.py deleted file mode 100644 index 56f84d153..000000000 --- a/tests/ev3dev/experimental/thread_tools.py +++ /dev/null @@ -1,48 +0,0 @@ -import uos - -from pybricks.experimental import run_parallel -from pybricks.tools import wait - -if uos.getenv("PYBRICKS_BUILD_ENV") == "docker-armel": - # qemu-user-static has issues with threads - print("SKIP") - raise SystemExit - - -def task1(): - wait(1000) - return "OK1" - - -def task2(): - wait(500) - return "OK2" - - -def task3(): - # Unhandled Exception should interrupt all other tasks - raise Exception("oops") - - -def task4(): - # Unhandled BaseException does not interrupt other tasks - raise SystemExit - - -result = run_parallel(task1, task2) -print(repr(result[task1])) -print(repr(result[task2])) - -try: - run_parallel(task1, task2, task3) -except RuntimeError as ex: - print(ex.args[0]) # message - print(repr(ex.args[1][task1])) - # sometimes task2 finishes before being interrupted - # print(repr(ex.args[1][task2])) - print(repr(ex.args[1][task3])) - -result = run_parallel(task1, task2, task4) -print(repr(result[task1])) -print(repr(result[task2])) -print(repr(result[task4])) diff --git a/tests/ev3dev/experimental/thread_tools.py.exp b/tests/ev3dev/experimental/thread_tools.py.exp deleted file mode 100644 index 917bcdbc1..000000000 --- a/tests/ev3dev/experimental/thread_tools.py.exp +++ /dev/null @@ -1,8 +0,0 @@ -'OK1' -'OK2' -An unhandled exception occurred in run_parallel -SystemExit() -Exception('oops',) -'OK1' -'OK2' -SystemExit() diff --git a/tests/ev3dev/grx-plugin.c b/tests/ev3dev/grx-plugin.c deleted file mode 100644 index a93fe0a2c..000000000 --- a/tests/ev3dev/grx-plugin.c +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2019-2020 The Pybricks Authors - -// GRX3 plugin to simulate LEGO MINDSTORMS EV3 screen for automated testing - -#include -#include -#include - -#define EV3_SCREEN_WIDTH 178 -#define EV3_SCREEN_HEIGHT 128 - -// Private symbols from GRX library -extern struct _GR_driverInfo _GrDriverInfo; -extern GrxVideoMode *_gr_select_mode(GrxVideoDriver *drv,int w,int h,int bpp, - int txt,unsigned int *ep); - - -// Empty device manager implementation - -#define TEST_TYPE_DEVICE_MANAGER test_device_manager_get_type() -G_DECLARE_FINAL_TYPE(TestDeviceManager, test_device_manager, TEST, DEVICE_MANAGER, GrxDeviceManager) - -struct _TestDeviceManager -{ - GrxDeviceManager parent_instance; -}; - -G_DEFINE_TYPE(TestDeviceManager, test_device_manager, GRX_TYPE_DEVICE_MANAGER) - -static void test_device_manager_class_init(TestDeviceManagerClass *klass) -{ -} - -static void test_device_manager_init(TestDeviceManager *self) -{ -} - - -// GRX3 plugin implementation - -static guint8 framebuffer[EV3_SCREEN_WIDTH * EV3_SCREEN_HEIGHT * 4]; - -static gboolean mem_setmode(GrxVideoMode *mp, int noclear) -{ - return TRUE; -} - -static GrxVideoModeExt ext = { - .mode = GRX_FRAME_MODE_LFB_32BPP_LOW, - .frame = framebuffer, - .cprec = { 8, 8, 8 }, - .cpos = { 0, 8, 16 }, - .flags = GRX_VIDEO_MODE_FLAG_MEMORY, - .setup = mem_setmode, -}; - -static GrxVideoMode modes[] = { - { - .present = TRUE, - .bpp = 32, - .width = EV3_SCREEN_WIDTH, - .height = EV3_SCREEN_HEIGHT, - .line_offset = EV3_SCREEN_WIDTH * 4, - .extended_info = &ext, - }, -}; - -static gboolean init(const char *options) -{ - TestDeviceManager *device_manager; - - device_manager = g_object_new(TEST_TYPE_DEVICE_MANAGER, NULL); - _GrDriverInfo.device_manager = GRX_DEVICE_MANAGER(device_manager); - - return TRUE; -} - -static void reset(void) -{ -} - -G_MODULE_EXPORT GrxVideoDriver grx_test_video_driver = { - .name = "test", - .modes = modes, - .n_modes = G_N_ELEMENTS(modes), - .init = init, - .reset = reset, - .select_mode = _gr_select_mode, -}; diff --git a/tests/ev3dev/lego-ev3-large-motor-port-a.umockdev b/tests/ev3dev/lego-ev3-large-motor-port-a.umockdev deleted file mode 100644 index 4659a3423..000000000 --- a/tests/ev3dev/lego-ev3-large-motor-port-a.umockdev +++ /dev/null @@ -1,101 +0,0 @@ -P: /devices/platform/ev3-ports/ev3-ports:outA/lego-port/port4/ev3-ports:outA:lego-ev3-l-motor/tacho-motor/motor0 -E: LEGO_ADDRESS=ev3-ports:outA -E: LEGO_DRIVER_NAME=lego-ev3-l-motor -E: SUBSYSTEM=tacho-motor -A: address=ev3-ports:outA -A: commands=run-forever run-to-abs-pos run-to-rel-pos run-timed run-direct stop reset -A: count_per_rot=360 -L: device=../../../ev3-ports:outA:lego-ev3-l-motor -A: driver_name=lego-ev3-l-motor -A: duty_cycle=0 -A: duty_cycle_sp=0 -A: hold_pid/Kd=0 -A: hold_pid/Ki=0 -A: hold_pid/Kp=80000 -A: max_speed=1050 -A: polarity=normal -A: position=0 -A: position_sp=0 -A: power/control=auto -A: power/runtime_active_time=0 -A: power/runtime_status=unsupported -A: power/runtime_suspended_time=0 -A: ramp_down_sp=0 -A: ramp_up_sp=0 -A: speed=0 -A: speed_pid/Kd=0 -A: speed_pid/Ki=60 -A: speed_pid/Kp=1000 -A: speed_sp=0 -A: state= -A: stop_action=coast -A: stop_actions=coast brake hold -A: time_sp=0 - -P: /devices/platform/ev3-ports/ev3-ports:outA/lego-port/port4/ev3-ports:outA:lego-ev3-l-motor -E: DEVTYPE=legoev3-motor -E: DRIVER=legoev3-motor -E: LEGO_ADDRESS=ev3-ports:outA -E: LEGO_DRIVER_NAME=lego-ev3-l-motor -E: MODALIAS=lego:legoev3-motor -E: OF_COMPATIBLE_N=0 -E: OF_FULLNAME=/ev3-ports/outA/motor -E: OF_NAME=motor -E: SUBSYSTEM=lego -L: driver=../../../../../../../bus/lego/drivers/legoev3-motor -A: modalias=lego:legoev3-motor -L: of_node=../../../../../../../firmware/devicetree/base/ev3-ports/outA/motor -A: power/control=auto -A: power/runtime_active_time=0 -A: power/runtime_status=unsupported -A: power/runtime_suspended_time=0 - -P: /devices/platform/ev3-ports/ev3-ports:outA/lego-port/port4 -E: DEVTYPE=ev3-output-port -E: LEGO_ADDRESS=ev3-ports:outA -E: LEGO_DRIVER_NAME=ev3-output-port -E: SUBSYSTEM=lego-port -A: address=ev3-ports:outA -L: device=../../../ev3-ports:outA -A: driver_name=ev3-output-port -A: mode=auto -A: modes=auto tacho-motor dc-motor led raw -A: power/control=auto -A: power/runtime_active_time=0 -A: power/runtime_status=unsupported -A: power/runtime_suspended_time=0 -A: status=tacho-motor - -P: /devices/platform/ev3-ports/ev3-ports:outA -E: DRIVER=ev3-output-port -E: MODALIAS=of:NoutATCev3dev,ev3-output-port -E: OF_COMPATIBLE_0=ev3dev,ev3-output-port -E: OF_COMPATIBLE_N=1 -E: OF_FULLNAME=/ev3-ports/outA -E: OF_NAME=outA -E: SUBSYSTEM=platform -L: driver=../../../../bus/platform/drivers/ev3-output-port -A: driver_override=(null) -A: modalias=of:NoutATCev3dev,ev3-output-port -L: of_node=../../../../firmware/devicetree/base/ev3-ports/outA -A: power/control=auto -A: power/runtime_active_time=0 -A: power/runtime_status=unsupported -A: power/runtime_suspended_time=0 - -P: /devices/platform/ev3-ports -E: DRIVER=ev3-ports -E: MODALIAS=of:Nev3-portsTCev3dev,ev3-ports -E: OF_COMPATIBLE_0=ev3dev,ev3-ports -E: OF_COMPATIBLE_N=1 -E: OF_FULLNAME=/ev3-ports -E: OF_NAME=ev3-ports -E: SUBSYSTEM=platform -L: driver=../../../bus/platform/drivers/ev3-ports -A: driver_override=(null) -A: modalias=of:Nev3-portsTCev3dev,ev3-ports -L: of_node=../../../firmware/devicetree/base/ev3-ports -A: power/control=auto -A: power/runtime_active_time=0 -A: power/runtime_status=unsupported -A: power/runtime_suspended_time=0 diff --git a/tests/ev3dev/media/font.py b/tests/ev3dev/media/font.py deleted file mode 100644 index b302c762d..000000000 --- a/tests/ev3dev/media/font.py +++ /dev/null @@ -1,45 +0,0 @@ -from pybricks.media.ev3dev import Font - -print(Font.DEFAULT.family) -print(Font.DEFAULT.style) -print(Font.DEFAULT.width) -print(Font.DEFAULT.height) -print(Font.DEFAULT.text_width("test")) -print(Font.DEFAULT.text_height("test")) - -# all args are optional -Font() - -# 1st arg can be None or str -Font("sans-serif") -Font(None) -Font(family="sans-serif") -Font(family=None) - -# 2nd arg is int -Font(None, 12) -Font(size=12) - -# 3rd arg is bool -Font(None, 12, False) -Font(bold=False) - -# 4th arg is bool -Font(None, 12, False, False) -Font(monospace=False) - -# 5th arg is None or str -Font(None, 12, False, False, None) -Font(None, 12, False, False, "en-US") -Font(lang=None) -Font(lang="en-US") - -# 6th arg is None or str with len() 4 -Font(None, 12, False, False, None, None) -Font(None, 12, False, False, None, "Latn") -Font(script=None) -Font(script="Latn") -try: - Font(script="bad") -except ValueError: - pass diff --git a/tests/ev3dev/media/font.py.exp b/tests/ev3dev/media/font.py.exp deleted file mode 100644 index 850a4c562..000000000 --- a/tests/ev3dev/media/font.py.exp +++ /dev/null @@ -1,6 +0,0 @@ -Lucida -Sans -16 -19 -30 -19 diff --git a/tests/ev3dev/media/image.py b/tests/ev3dev/media/image.py deleted file mode 100644 index f5d5f6d0e..000000000 --- a/tests/ev3dev/media/image.py +++ /dev/null @@ -1,238 +0,0 @@ -import uos - -from pybricks.parameters import Color -from pybricks.media.ev3dev import Font, Image - -# Working directory is top-level tests directory -TEST_IMAGE = "../../tests/ev3dev/media/test.png" - -# requires one argument -try: - Image() -except TypeError as ex: - print(ex) - -# if argument is string, load from file -img = Image(TEST_IMAGE) - -# error if file does not exist -try: - img = Image("bad.png") -except OSError as ex: - print(ex) - -# omitting file extension is OK -img = Image(TEST_IMAGE[:-4]) - -# if argument is Image, a copy is created -img = Image(img) - -# if argument is Image and sub=True, a sub-image is created -sub = Image(img, sub=True, x1=10, y1=10, x2=20, y2=20) -print(sub.width, sub.height) - -# static method for creating blank image -img = Image.empty(160, 120) - -# default args for empty are same size as screen -empty = Image.empty() -screen = Image("_screen_") -print(empty.width == screen.width) -print(empty.height == screen.height) - - -# Test properties - -print(img.width) -print(img.height) - - -# Test clear() - -img.clear() - - -# Test draw_pixel() - -# two required arguments -img.draw_pixel(0, 0) -img.draw_pixel(x=0, y=0) -try: - img.draw_pixel(0) -except TypeError as ex: - print(ex) - -# 3rd argument is kwarg -img.draw_pixel(0, 0, Color.BLACK) -img.draw_pixel(0, 0, color=Color.BLACK) - - -# Test draw_line() - -# four required arguments -img.draw_line(0, 0, 0, 0) -img.draw_line(x1=0, y1=0, x2=0, y2=0) -try: - img.draw_line(0, 0, 0) -except TypeError as ex: - print(ex) - -# 5th argument is kwarg -img.draw_line(0, 0, 0, 0, 1) -img.draw_line(0, 0, 0, 0, width=1) - -# 6th argument is kwarg -img.draw_line(0, 0, 0, 0, 1, Color.BLACK) -img.draw_line(0, 0, 0, 0, color=Color.BLACK) - - -# Test draw_box() - -# four required arguments -img.draw_box(0, 0, 0, 0) -img.draw_box(x1=0, y1=0, x2=0, y2=0) -try: - img.draw_box(0, 0, 0) -except TypeError as ex: - print(ex) - -# 5th argument is kwarg -img.draw_box(0, 0, 0, 0, 0) -img.draw_box(0, 0, 0, 0, r=0) - -# 6th argument is kwarg -img.draw_box(0, 0, 0, 0, 0, False) -img.draw_box(0, 0, 0, 0, fill=False) - -# 6th argument is kwarg -img.draw_box(0, 0, 0, 0, 0, False, Color.BLACK) -img.draw_box(0, 0, 0, 0, color=Color.BLACK) - - -# Test draw_circle() - -# three required arguments -img.draw_circle(0, 0, 0) -img.draw_circle(x=0, y=0, r=0) -try: - img.draw_circle(0, 0) -except TypeError as ex: - print(ex) - -# 4th argument is kwarg -img.draw_circle(0, 0, 0, False) -img.draw_circle(0, 0, 0, fill=False) - -# 5th argument is kwarg -img.draw_circle(0, 0, 0, False, Color.BLACK) -img.draw_circle(0, 0, 0, color=Color.BLACK) - - -# Test draw_image() - -# three required arguments -img.draw_image(0, 0, img) -img.draw_image(0, 0, TEST_IMAGE) -img.draw_image(x=0, y=0, source=img) -try: - img.draw_image(0, 0) -except TypeError as ex: - print(ex) - -# 4th argument is kwarg and can be Color or None -img.draw_image(0, 0, img, None) -img.draw_image(0, 0, img, Color.WHITE) -img.draw_image(0, 0, img, transparent=None) -img.draw_image(0, 0, img, transparent=Color.WHITE) - - -# Test load_image() - -# one required argument, Image or str -img.load_image(img) -img.load_image(TEST_IMAGE) -try: - img.load_image() -except TypeError as ex: - print(ex) -try: - img.load_image(0) -except TypeError as ex: - print(ex) - - -# Test draw_text() - -# three required arguments -img.draw_text(0, 0, "") -img.draw_text(x=0, y=0, text="") -try: - img.draw_text(0, 0) -except TypeError as ex: - print(ex) - -# 4th argument is kwarg -img.draw_text(0, 0, "", Color.BLACK) -img.draw_text(0, 0, "", text_color=Color.BLACK) - -# 5th argument is kwarg -img.draw_text(0, 0, "", Color.BLACK, Color.WHITE) -img.draw_text(0, 0, "", background_color=Color.WHITE) - - -# Test set_font() - -# one required argument -img.set_font(Font.DEFAULT) -try: - img.set_font() -except TypeError as ex: - print(ex) - - -# Test print() - -# no required arguments -img.print() - -# positional args take any object type -img.print("", 0, False, img, {}, []) - -# keyword-only arg end -img.print(end="\n") -img.print("", end="\n") - -# keyword-only arg sep -img.print(sep=" ") -img.print("", sep=" ") - - -# Test save() - -# one required argument -try: - img.save() -except TypeError as ex: - print(ex) - -# actually creates file on disk -img.save("test.png") -uos.stat("test.png") -uos.remove("test.png") - -# automatically adds file extension if missing -img.save("test") -uos.stat("test.png") -uos.remove("test.png") - -# upper-case is OK too -img.save("TEST.PNG") -uos.stat("TEST.PNG") -uos.remove("TEST.PNG") - -# illegal name or permissions issue gives OSError -try: - # this should fail because we are not root - img.save("/test.png") -except OSError as ex: - print(ex) diff --git a/tests/ev3dev/media/image.py.exp b/tests/ev3dev/media/image.py.exp deleted file mode 100644 index 6ab97fcbc..000000000 --- a/tests/ev3dev/media/image.py.exp +++ /dev/null @@ -1,18 +0,0 @@ -'source' argument required -'bad.png' is not a .png file -11 11 -True -True -160 -120 -'y' argument required -'y2' argument required -'y2' argument required -'r' argument required -'source' argument required -function takes 2 positional arguments but 1 were given -source must be Image or str -'text' argument required -function takes 2 positional arguments but 1 were given -function takes 2 positional arguments but 1 were given -Failed to save image: Failed to open '/test.png' diff --git a/tests/ev3dev/media/test.png b/tests/ev3dev/media/test.png deleted file mode 100644 index 065bdbb53ab56c4a8c8eb50f4e1efe1a3b5bd850..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2520 zcmbVOcTm&W7DfpMB_Nt$zy-;mMpOtzU_)_%kc5s9BE`ia2^flmuCRazK|nxZH9`oO zB^ZNJT}pyf8>|9L7wIlY4M;B`@Pzl#|P!ilc+2?4jd_ zBqStct*x*GVCMi5DZL+9w_gXMf$d%aTuD=p zFKY{^RQ!l;;TAzO+O@!N;3y$s5qgare$5*Z;TP_Uu(Y;!^hR9+1MwWJvF60cp#`>| z9klbixCj|O2V*Epl$X40ekC7fVg|`RDs`|4q|YJ26kw)`%XZj=gU1h3?t)2XUZ+w) zO(&5D6r?^DjT0Qp5y(_!n%~*y%9>x7-c7#pi_(yxBlbjMB2~m@cTCiW1wcdS2yN2# z+c=cO8wu$HX4(?;ee#evk_0FL5J`mMzt!gdG5w|fKRg%?mX_f333U3-_O`=_vz@(t zh;l?|=yvjui4(oX162lQv{Y4ALJuWIZ+`u0V@?5*BQ&7vAGddPb+xy*cX4qsGc)t{ zeu~MD`-LqyyS@8uhfF3*N=kOs?EN|hK72xc&!W`j_RglJmR4tTv((jFYt!vKTjp*i zs>@doWL_l@&`I1hn2*oQ!f-VZw63=H$=i_;55EY07tZWt90=I7^s_kG}< z#KfAHFMoB@P=24An=5?rq`0`)nLxOM8GmdTM*Tf|d~6IMFHQ0Cl97>#j*7zf*=A;D ze){z3InB?{&&aiz5`w|dnM`Pfw-hcu^=H@-H0|R9AB``HllaL;k@N@e`3YHmR|RL*+CY zZFhIqDE?>)Xw;8Fp_2zjYQkg<>+gqhz28c;O@$syOC)D!W?uI6%zLArh>33$@OV?5d8Ql2X`M4WVzE=q znnkjl67=_(HKyi|1*$y*1L!9tmYu-2TW!wanHKuY8SurlW{LtFKJNikRwYEwp>eF( z^~J+d;oKZ15y&h4v{)=Yz(skyj0?1~v(p=JmktYC^Ln4IZ(y(~64~;4==A*+A|=Rg zZA`7Rl)-?_7RDK;l8)Z9pyWGue%1$p!EgnIZ(A!~Boe2xva+lUWoml+U6O1|OG`K? z4;?}eXjz--ym8`bw{Ji|K$qDzNqMEhBI5o+74M+U+;0okw*}3ZE?QCSXkU|t{4nREz?16 zjlWCwmIdmkS7+t9+||{!I9lhFpO9d2^(s3SR+9vm2EBXtu4zk0j^5|LAzJ$5#nn1I zDqja;9I^QLCMP)=oTCLa(v7*2q9Wa_-m23oCXrnv#^+bJFUfsLPnSz5XR%l?&(`d* z<>g@52?Yh*tF&;CNF-u7Z_%Y>u3WhS!MAwphF`L>lGZ7^=cKJ48yjoXyC7bh>E@lZ zOrQP8%Fe!vnwp$+l>W5GG{>Mgi=P{cRnsQWhVEVPl5SrO4Gl-x%a<>EK}!gQbUOWm zDUWa#hsf)+EVZ|_WwcE>y9T?tW!oVy2=09eM$eM=t?Y<`407+22Y?I$J$~;-7Mrbt zD<%*KU9@MH@;+s-O>h6O!PHgXn(u$1KGNFiPc&r2lmX8K8h=~kXbO zpLPJC(_3JF=@%2SwxVLvX#G!Nk&%(Q8RrU}&Sg$dPb(&Adc1TjbumVxIZGTuA^veE zegrv=4h+uK6CAOV$6~Qfc|iNgCIUWK19iOVN57N&s_e;>Oh?S zsWWG|hld3;ZY7DV%i2DVUPwsiU+?cRg%+IL>gHNbgm%Rn9GNt)Wipw&sOR+v8bH&@j()vtLgE zq3(4&=W@A0qqTiKJw5&X{lmjMzy#d82eGuYgv~B3neyQ7L&i~|l4d@7%aJB?OxYdL z(z6Q>@#o!8%(}X|jQ+Ny#l^r?J~-ojuYzCXj37GO|URTbWxs-T#pucrq9lr4|2`e=7` zs!drgnbH8@?omZWbjwnL5W#F~d1TvQ{L!?(A##O6A|ayY7bhoSDk`N6*82z$<8Jd8 z0Ps&__|RzW-nuF(DpLE+Jv=+2v8=;s&SUFk=3&}cUz5e9`$%+2{z zslQRm(aIe;`qyeK>|>)FHZ%Fka+W*QuCJ?d z5&&S%Jnu?v&ynI@zryofrxH&c1-`n{AFJhRW1~7$OgbD{zf(c4)R~7e{qn% h(UbqhV|j1i-agx#>F&pkAK3g!xvX&x*fI=>{!gYnkdy!b diff --git a/tests/ev3dev/messaging/compat.py b/tests/ev3dev/messaging/compat.py deleted file mode 100644 index 05b6a63a8..000000000 --- a/tests/ev3dev/messaging/compat.py +++ /dev/null @@ -1,89 +0,0 @@ -# Test classes used for EV3/NXT standard firmware compatibility - -from pybricks.messaging import LogicMailbox, NumericMailbox, TextMailbox - - -class MockConnection: - _bricks = {} - - def __init__(self, brick): - self._name = brick - self._bricks[brick] = {} - - def send_to_mailbox(self, brick, mbox, payload): - if isinstance(payload, str): - payload = payload.encode() - if brick is None: - for k, v in self._bricks.items(): - if k != self._name: - v[mbox] = payload - else: - self._bricks[brick][mbox] = payload - - def read_from_mailbox(self, mbox): - return self._bricks[self._name].get(mbox) - - def print_payload(self, mbox): - print(self._bricks[self._name].get(mbox)) - - -SERVER = "server" -CLIENT = "client" - -LOGIC = "logic" -NUMERIC = "numeric" -TEXT = "text" - - -server = MockConnection(SERVER) -server_logic = LogicMailbox(LOGIC, server) -server_numeric = NumericMailbox(NUMERIC, server) -server_text = TextMailbox(TEXT, server) - - -client = MockConnection(CLIENT) -client_logic = LogicMailbox(LOGIC, client) -client_numeric = NumericMailbox(NUMERIC, client) -client_text = TextMailbox(TEXT, client) - - -# mailbox that has not received a value returns None -print(client_logic.read()) - -server_logic.send(True) -# should be True -print(client_logic.read()) -client.print_payload(LOGIC) - -server_logic.send(None) -# should be False - None is falsy -print(client_logic.read()) -client.print_payload(LOGIC) - - -# mailbox that has not received a value returns None -print(client_numeric.read()) - -server_numeric.send(1.2) -# should be 1.200000047683716 - does not have exact representation -print(client_numeric.read()) -client.print_payload(NUMERIC) - -server_numeric.send(5) -# should be 5.0 - int is converted to float -print(client_numeric.read()) -client.print_payload(NUMERIC) - - -# mailbox that has not received a value returns None -print(client_text.read()) - -server_text.send("hi") -# should be hi -print(client_text.read()) -client.print_payload(TEXT) - -server_text.send(5) -# should be 5 - other types are converted to string -print(client_text.read()) -client.print_payload(TEXT) diff --git a/tests/ev3dev/messaging/compat.py.exp b/tests/ev3dev/messaging/compat.py.exp deleted file mode 100644 index 612854ac8..000000000 --- a/tests/ev3dev/messaging/compat.py.exp +++ /dev/null @@ -1,15 +0,0 @@ -None -True -b'\x01' -False -b'\x00' -None -1.200000047683716 -b'\x9a\x99\x99?' -5.0 -b'\x00\x00\xa0@' -None -hi -b'hi\x00' -5 -b'5\x00' diff --git a/tests/ev3dev/motor/motor.py b/tests/ev3dev/motor/motor.py deleted file mode 100644 index 60187e38e..000000000 --- a/tests/ev3dev/motor/motor.py +++ /dev/null @@ -1,79 +0,0 @@ -from pybricks.ev3devices import Motor -from pybricks.parameters import Port -from pybricks.tools import wait - -IIO_BASE = ( - "/sys/devices/platform/soc@1c00000/ti-pruss/1c32000.pru1" - "/remoteproc/remoteproc0/virtio0/virtio0.ev3-tacho-rpmsg.-1.0" - "/iio:device1/" -) -TACHO_BASE = ( - "/sys/devices/platform/ev3-ports/ev3-ports:outA/lego-port" - "/port4/ev3-ports:outA:lego-ev3-l-motor/tacho-motor/motor0/" -) - - -def write_iio(attr, value): - with open(IIO_BASE + attr, "w") as f: - f.write(value + "\n") - - -def print_iio(attr): - with open(IIO_BASE + attr, "r") as f: - print(f.read().strip()) - - -def write_tacho(attr, value): - with open(TACHO_BASE + attr, "w") as f: - f.write(value + "\n") - - -def print_tacho(attr): - with open(TACHO_BASE + attr, "r") as f: - print(f.read().strip()) - - -m = Motor(Port.A) - - -# testing angle - -print(m.angle()) # expect 0 - -write_iio("in_count0_raw", "360") -wait(5) # Values may be cached briefly -print(m.angle()) # expect 180 - -# testing stalled - -print(m.control.stalled()) # expect False - - -# testing direct control of duty cycle - -m.dc(50) -print_tacho("command") # expect "run-direct" -print_tacho("duty_cycle_sp") # expect 50 - -m.dc(100) -print_tacho("command") # expect "run-direct" -print_tacho("duty_cycle_sp") # expect 100 - -# duty cycle > 100 is clipped -m.dc(101) -print_tacho("command") # expect "run-direct" -print_tacho("duty_cycle_sp") # expect 100 - -m.dc(-100) -print_tacho("command") # expect "run-direct" -print_tacho("duty_cycle_sp") # expect -100 - -# duty cycle less than -100 is clipped -m.dc(-101) -print_tacho("command") # expect "run-direct" -print_tacho("duty_cycle_sp") # expect -100 - - -# testing __str__/__repr__ - -print(m) diff --git a/tests/ev3dev/motor/motor.py.exp b/tests/ev3dev/motor/motor.py.exp deleted file mode 100644 index 0f3a62fa2..000000000 --- a/tests/ev3dev/motor/motor.py.exp +++ /dev/null @@ -1,14 +0,0 @@ -0 -180 -False -run-direct -50 -run-direct -100 -run-direct -100 -run-direct --100 -run-direct --100 -Motor(Port.A, Direction.CLOCKWISE) diff --git a/tests/ev3dev/parameters/button.py b/tests/ev3dev/parameters/button.py deleted file mode 100644 index 9ea6d0a10..000000000 --- a/tests/ev3dev/parameters/button.py +++ /dev/null @@ -1,12 +0,0 @@ -from pybricks.parameters import Button - -# "enums" print exactly the same as what we write in code "Button.RIGHT" -print(Button.RIGHT) - -print(Button.LEFT == Button.LEFT) -print(Button.DOWN != Button.DOWN) -print(Button.LEFT == Button.DOWN) -print(Button.LEFT != Button.DOWN) - -# Internally, these may have the same value, but externally, they are not equal -print(Button.BEACON == Button.UP) diff --git a/tests/ev3dev/parameters/button.py.exp b/tests/ev3dev/parameters/button.py.exp deleted file mode 100644 index 6503c44cf..000000000 --- a/tests/ev3dev/parameters/button.py.exp +++ /dev/null @@ -1,6 +0,0 @@ -Button.RIGHT -True -False -False -True -False diff --git a/tests/ev3dev/test-wrapper.sh b/tests/ev3dev/test-wrapper.sh deleted file mode 100755 index e2e4ee9c6..000000000 --- a/tests/ev3dev/test-wrapper.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -# -# Runs pybricks-micropython with ev3dev-mocks-run for testing - -DIR=$(dirname "$(readlink -f $0)") - -export EV3DEV_MOCKS_UMOCKDEV_RUN_ARGS="-d $DIR/lego-ev3-large-motor-port-a.umockdev" - -exec ev3dev-mocks-run "$PYBRICKS_MICROPYTHON" "$@" diff --git a/tests/ev3dev/tools/matrix.py b/tests/ev3dev/tools/matrix.py deleted file mode 100644 index 7759b4a17..000000000 --- a/tests/ev3dev/tools/matrix.py +++ /dev/null @@ -1,102 +0,0 @@ -from pybricks.tools import Matrix, vector, cross -from pybricks.parameters import Axis - -# Test backwards compatibility imports -from pybricks.geometry import vector as _vector, Matrix as _Matrix, Axis as _Axis - -assert Matrix == _Matrix -assert vector == _vector -assert Axis == _Axis - -# Basic matrix algebra -A = Matrix( - [ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - ] -) -B = -A -C = A - A.T - -print("A =", A) -print("B = -A =", B) -print("A.T =", A.T) -print("A + B =", A + B) -print("C = A - A.T =", C) -print("C + C.T =", C + C.T) -print("A * A.T =", A * A.T) -print("A.shape =", A.shape) -print("A * 3 =", A * 3) -print("3 * A =", 3 * A) -print("cross(Axis.X * 4, Axis.Y * 3) = ", cross(Axis.X * 4, Axis.Y * 3)) - -# Reading elements -print("B[0, 1] =", B[0, 1]) -print("B.T[0, 1] =", B.T[0, 1]) - -# Vector basics -b = vector(3, 4, 0) -c = b.T -print("b = vector(3, 4, 0) =", b) -print("b.shape =", b.shape) -print("abs(b) =", abs(b)) -print("[v for v in b * 2] =", [v for v in b * 2]) -print("c = b.T", c) -print("A * b =", A * b) - -# Dealing with resulting scalar types -print("b.T * b =", b.T * b) -print("type(b.T * b) =", type(b.T * b)) -print("b.T * A * b =", b.T * A * b) -print("(b.T * A * b) * A / 2 =", (b.T * A * b) * A / 2) - -# Nonsquare matrices -D = Matrix( - [ - [0, 1, 0, 2], - [3, 0, 4, 0], - ] -) -print("D =", D) -print("D.shape =", D.shape) -print("D.T.shape =", D.T.shape) -print("D.T * D =", D.T * D) -print("D * D.T =", D * D.T) - -# Test catch of dimension errors -try: - b - c -except ValueError: - pass -try: - b * A -except ValueError: - pass - -# 1x1 matrix is scalar and is converted to float. - -print(type(Matrix([[0]]))) - -# 0-sized dimensions raise errors. - -try: - Matrix([]) -except ValueError: - print("ValueError") - -try: - Matrix([[]]) -except ValueError: - print("ValueError") - -# Mismatched dimensions raise error. - -try: - Matrix([[0], [1, 2]]) -except ValueError: - print("ValueError") - -# iterator -print(*B) -print(*B.T) diff --git a/tests/ev3dev/tools/matrix.py.exp b/tests/ev3dev/tools/matrix.py.exp deleted file mode 100644 index eb024c781..000000000 --- a/tests/ev3dev/tools/matrix.py.exp +++ /dev/null @@ -1,99 +0,0 @@ -A = Matrix([ - [ 1.000, 2.000, 3.000], - [ 4.000, 5.000, 6.000], - [ 7.000, 8.000, 9.000], -]) -B = -A = Matrix([ - [ -1.000, -2.000, -3.000], - [ -4.000, -5.000, -6.000], - [ -7.000, -8.000, -9.000], -]) -A.T = Matrix([ - [ 1.000, 4.000, 7.000], - [ 2.000, 5.000, 8.000], - [ 3.000, 6.000, 9.000], -]) -A + B = Matrix([ - [ 0.000, 0.000, 0.000], - [ 0.000, 0.000, 0.000], - [ 0.000, 0.000, 0.000], -]) -C = A - A.T = Matrix([ - [ 0.000, -2.000, -4.000], - [ 2.000, 0.000, -2.000], - [ 4.000, 2.000, 0.000], -]) -C + C.T = Matrix([ - [ 0.000, 0.000, 0.000], - [ 0.000, 0.000, 0.000], - [ 0.000, 0.000, 0.000], -]) -A * A.T = Matrix([ - [ 14.000, 32.000, 50.000], - [ 32.000, 77.000, 122.000], - [ 50.000, 122.000, 194.000], -]) -A.shape = (3, 3) -A * 3 = Matrix([ - [ 3.000, 6.000, 9.000], - [ 12.000, 15.000, 18.000], - [ 21.000, 24.000, 27.000], -]) -3 * A = Matrix([ - [ 3.000, 6.000, 9.000], - [ 12.000, 15.000, 18.000], - [ 21.000, 24.000, 27.000], -]) -cross(Axis.X * 4, Axis.Y * 3) = Matrix([ - [ 0.000], - [ 0.000], - [ 12.000], -]) -B[0, 1] = -2.0 -B.T[0, 1] = -4.0 -b = vector(3, 4, 0) = Matrix([ - [ 3.000], - [ 4.000], - [ 0.000], -]) -b.shape = (3, 1) -abs(b) = 5.0 -[v for v in b * 2] = [6.0, 8.0, 0.0] -c = b.T Matrix([ - [ 3.000, 4.000, 0.000], -]) -A * b = Matrix([ - [ 11.000], - [ 32.000], - [ 53.000], -]) -b.T * b = 25.0 -type(b.T * b) = -b.T * A * b = 161.0 -(b.T * A * b) * A / 2 = Matrix([ - [ 80.500, 161.000, 241.500], - [ 322.000, 402.500, 483.000], - [ 563.500, 644.000, 724.500], -]) -D = Matrix([ - [ 0.000, 1.000, 0.000, 2.000], - [ 3.000, 0.000, 4.000, 0.000], -]) -D.shape = (2, 4) -D.T.shape = (4, 2) -D.T * D = Matrix([ - [ 9.000, 0.000, 12.000, 0.000], - [ 0.000, 1.000, 0.000, 2.000], - [ 12.000, 0.000, 16.000, 0.000], - [ 0.000, 2.000, 0.000, 4.000], -]) -D * D.T = Matrix([ - [ 5.000, 0.000], - [ 0.000, 25.000], -]) - -ValueError -ValueError -ValueError --1.0 -2.0 -3.0 -4.0 -5.0 -6.0 -7.0 -8.0 -9.0 --9.0 -8.0 -7.0 -6.0 -5.0 -4.0 -3.0 -2.0 -1.0