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 065bdbb53..000000000 Binary files a/tests/ev3dev/media/test.png and /dev/null differ 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