diff --git a/atmel-samd/Makefile b/atmel-samd/Makefile index 1e5fe110d0f62..c8f3bc690c78a 100644 --- a/atmel-samd/Makefile +++ b/atmel-samd/Makefile @@ -284,6 +284,8 @@ SRC_SHARED_MODULE = \ bitbangio/OneWire.c \ bitbangio/SPI.c \ busio/OneWire.c \ + gamepad/__init__.c \ + gamepad/GamePad.c \ os/__init__.c \ random/__init__.c \ storage/__init__.c \ diff --git a/atmel-samd/mpconfigport.h b/atmel-samd/mpconfigport.h index e99d190be5ca5..fc061d1cb896c 100644 --- a/atmel-samd/mpconfigport.h +++ b/atmel-samd/mpconfigport.h @@ -152,6 +152,7 @@ extern const struct _mp_obj_module_t neopixel_write_module; extern const struct _mp_obj_module_t uheap_module; extern const struct _mp_obj_module_t ustack_module; extern const struct _mp_obj_module_t samd_module; +extern const struct _mp_obj_module_t gamepad_module; extern const struct _mp_obj_module_t touchio_module; extern const struct _mp_obj_module_t usb_hid_module; @@ -171,10 +172,13 @@ extern const struct _mp_obj_module_t usb_hid_module; #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) #define MICROPY_PY_SYS_MAXSIZE (1) #define MICROPY_CPYTHON_COMPAT (1) + // Scan gamepad every 32ms + #define CIRCUITPY_GAMEPAD_TICKS 0x1f #define EXTRA_BUILTIN_MODULES \ { MP_OBJ_NEW_QSTR(MP_QSTR_audioio), (mp_obj_t)&audioio_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_audiobusio), (mp_obj_t)&audiobusio_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_gamepad),(mp_obj_t)&gamepad_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_nvm), (mp_obj_t)&cpy_nvm_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_pulseio), (mp_obj_t)&pulseio_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_bitbangio), (mp_obj_t)&bitbangio_module } diff --git a/atmel-samd/tick.c b/atmel-samd/tick.c index cbe72abc6e197..e97da07303fcd 100644 --- a/atmel-samd/tick.c +++ b/atmel-samd/tick.c @@ -1,4 +1,5 @@ #include "autoreload.h" +#include "shared-module/gamepad/__init__.h" #include "tick.h" @@ -17,6 +18,11 @@ static void ms_tick(struct tc_module *const module_inst) { #ifdef CIRCUITPY_AUTORELOAD_DELAY_MS autoreload_tick(); #endif + #ifdef CIRCUITPY_GAMEPAD_TICKS + if (!(ticks_ms & CIRCUITPY_GAMEPAD_TICKS)) { + gamepad_tick(); + } + #endif } void tick_init() { diff --git a/shared-bindings/gamepad/GamePad.c b/shared-bindings/gamepad/GamePad.c new file mode 100644 index 0000000000000..bdc3359fb698a --- /dev/null +++ b/shared-bindings/gamepad/GamePad.c @@ -0,0 +1,146 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Radomir Dopieralski for Adafruit Industries + * + * 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 "py/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "shared-module/gamepad/GamePad.h" +#include "GamePad.h" + + +gamepad_obj_t* gamepad_singleton = NULL; + +//| .. currentmodule:: gamepad +//| +//| :class:`GamePad` -- Scan buttons for presses +//| ============================================ +//| +//| Usage:: +//| +//| import board +//| import digitalio +//| import gamepad +//| import time +//| +//| B_UP = 1 << 0 +//| B_DOWN = 1 << 1 +//| +//| +//| pad = gamepad.GamePad( +//| digitalio.DigitalInOut(board.D0), +//| digitalio.DigitalInOut(board.D1), +//| ) +//| +//| y = 0 +//| while True: +//| buttons = pad.get_pressed() +//| if buttons & B_UP: +//| y -= 1 +//| print(y) +//| elif buttons & B_DOWN: +//| y += 1 +//| print(y) +//| time.sleep(0.1) +//| while pad.get_pressed(): +//| # Wait for all buttons to be released. +//| time.sleep(0.1) +//| + +//| .. class:: GamePad([b1[, b2[, b3[, b4[, b5[, b6[, b7[, b8]]]]]]]]) +//| +//| Initializes button scanning routines. +//| +//| The ``b1``-``b8`` parameters are ``DigitalInOut`` objects, which +//| immediately get switched to input with a pull-up, and then scanned +//| regularly for button presses. The order is the same as the order of +//| bits returned by the ``get_pressed`` function. You can re-initialize +//| it with different keys, then the new object will replace the previous +//| one. +//| +//| The basic feature required here is the ability to poll the keys at +//| regular intervals (so that de-bouncing is consistent) and fast enough +//| (so that we don't miss short button presses) while at the same time +//| letting the user code run normally, call blocking functions and wait +//| on delays. +//| +//| They button presses are accumulated, until the ``get_pressed`` method +//| is called, at which point the button state is cleared, and the new +//| button presses start to be recorded. +//| +STATIC mp_obj_t gamepad_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *args) { + if (!gamepad_singleton) { + gamepad_singleton = m_new_obj(gamepad_obj_t); + gamepad_singleton->base.type = &gamepad_type; + } + gamepad_init(n_args, args); + return MP_OBJ_FROM_PTR(gamepad_singleton); +} + + +//| .. method:: get_pressed() +//| +//| Get the status of buttons pressed since the last call and clear it. +//| +//| Returns an 8-bit number, with bits that correspond to buttons, +//| which have been pressed (or held down) since the last call to this +//| function set to 1, and the remaining bits set to 0. Then it clears +//| the button state, so that new button presses (or buttons that are +//| held down) can be recorded for the next call. +//| +STATIC mp_obj_t gamepad_get_pressed(mp_obj_t self_in) { + gamepad_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t gamepad = MP_OBJ_NEW_SMALL_INT(self->pressed); + self->pressed = 0; + return gamepad; +} +MP_DEFINE_CONST_FUN_OBJ_1(gamepad_get_pressed_obj, gamepad_get_pressed); + + +//| .. method:: deinit() +//| +//| Disable button scanning. +//| +STATIC mp_obj_t gamepad_deinit(mp_obj_t self_in) { + gamepad_singleton = NULL; + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(gamepad_deinit_obj, gamepad_deinit); + + +STATIC mp_obj_t gamepad_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *args); +STATIC const mp_rom_map_elem_t gamepad_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_get_pressed), MP_ROM_PTR(&gamepad_get_pressed_obj)}, + { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&gamepad_deinit_obj)}, +}; +STATIC MP_DEFINE_CONST_DICT(gamepad_locals_dict, gamepad_locals_dict_table); +const mp_obj_type_t gamepad_type = { + { &mp_type_type }, + .name = MP_QSTR_GamePad, + .make_new = gamepad_make_new, + .locals_dict = (mp_obj_dict_t*)&gamepad_locals_dict, +}; + diff --git a/shared-bindings/gamepad/GamePad.h b/shared-bindings/gamepad/GamePad.h new file mode 100644 index 0000000000000..172c95ace85ff --- /dev/null +++ b/shared-bindings/gamepad/GamePad.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Radomir Dopieralski for Adafruit Industries + * + * 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. + */ + + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_GAMEPAD_GAMEPAD_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_GAMEPAD_GAMEPAD_H + +extern const mp_obj_type_t gamepad_type; + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_GAMEPAD_GAMEPAD_H diff --git a/shared-bindings/gamepad/__init__.c b/shared-bindings/gamepad/__init__.c new file mode 100644 index 0000000000000..0c99d0d52bea8 --- /dev/null +++ b/shared-bindings/gamepad/__init__.c @@ -0,0 +1,54 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Radomir Dopieralski for Adafruit Industries + * + * 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 "py/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "GamePad.h" + + +//| :mod:`gamepad` --- Button handling +//| ================================== +//| +//| .. module:: gamepad +//| :synopsis: Button handling +//| :platform: SAMD21 +//| +//| .. toctree:: +//| :maxdepth: 3 +//| +//| GamePad +//| +STATIC const mp_rom_map_elem_t gamepad_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_gamepad) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GamePad), MP_ROM_PTR(&gamepad_type)}, +}; +STATIC MP_DEFINE_CONST_DICT(gamepad_module_globals, + gamepad_module_globals_table); + +const mp_obj_module_t gamepad_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&gamepad_module_globals, +}; diff --git a/shared-bindings/index.rst b/shared-bindings/index.rst index 49b6ce5bc3ab4..556626268bbce 100644 --- a/shared-bindings/index.rst +++ b/shared-bindings/index.rst @@ -21,9 +21,10 @@ Module / Port SAMD21 SAMD21 Express ESP8266 `board` **Yes** **Yes** **Yes** `busio` **Yes** **Yes** **Yes** `digitalio` **Yes** **Yes** **Yes** -`microcontroller` **Yes** **Yes** **Yes** +`gamepad` No **Yes** No +`microcontroller` **Yes** **Yes** **Yes** `multiterminal` No No **Yes** -`neopixel_write` **Yes** **Yes** **Yes** +`neopixel_write` **Yes** **Yes** **Yes** `nvm` No **Yes** No `os` **Yes** **Yes** **Yes** `pulseio` No **Yes** No diff --git a/shared-module/gamepad/GamePad.c b/shared-module/gamepad/GamePad.c new file mode 100644 index 0000000000000..3a2b8a3fe9264 --- /dev/null +++ b/shared-module/gamepad/GamePad.c @@ -0,0 +1,46 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Radomir Dopieralski for Adafruit Industries + * + * 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 "__init__.h" +#include "GamePad.h" + +#include "shared-bindings/digitalio/Pull.h" +#include "shared-bindings/digitalio/DigitalInOut.h" + + +void gamepad_init(size_t n_pins, const mp_obj_t* pins) { + for (size_t i=0; i<8; ++i) { + gamepad_singleton->pins[i] = NULL; + } + for (size_t i=0; ipins[i] = pin; + common_hal_digitalio_digitalinout_switch_to_input(pin, PULL_UP); + } + gamepad_singleton->last = 0; +} diff --git a/shared-module/gamepad/GamePad.h b/shared-module/gamepad/GamePad.h new file mode 100644 index 0000000000000..e5f709134de1d --- /dev/null +++ b/shared-module/gamepad/GamePad.h @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Radomir Dopieralski for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_GAMEPAD_GAMEPAD_H +#define MICROPY_INCLUDED_GAMEPAD_GAMEPAD_H + +#include + +#include "shared-bindings/digitalio/DigitalInOut.h" + +typedef struct { + mp_obj_base_t base; + digitalio_digitalinout_obj_t* pins[8]; + volatile uint8_t last; + volatile uint8_t pressed; +} gamepad_obj_t; + +extern gamepad_obj_t* gamepad_singleton; + +void gamepad_init(size_t n_pins, const mp_obj_t* pins); + +#endif // MICROPY_INCLUDED_GAMEPAD_GAMEPAD_H diff --git a/shared-module/gamepad/__init__.c b/shared-module/gamepad/__init__.c new file mode 100644 index 0000000000000..1aebf611d3935 --- /dev/null +++ b/shared-module/gamepad/__init__.c @@ -0,0 +1,51 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Radomir Dopieralski for Adafruit Industries + * + * 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 "__init__.h" +#include "GamePad.h" + +#include "shared-bindings/digitalio/DigitalInOut.h" + + +void gamepad_tick(void) { + if (!gamepad_singleton) { + return; + } + uint8_t gamepad_current = 0; + for (int i=0; i<8; ++i) { + digitalio_digitalinout_obj_t* pin = gamepad_singleton->pins[i]; + if (!pin) { + break; + } + if (!common_hal_digitalio_digitalinout_get_value(pin)) { + gamepad_current |= 1<pressed |= gamepad_singleton->last & gamepad_current; + gamepad_singleton->last = gamepad_current; +} diff --git a/shared-module/gamepad/__init__.h b/shared-module/gamepad/__init__.h new file mode 100644 index 0000000000000..eacd7236699b0 --- /dev/null +++ b/shared-module/gamepad/__init__.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_GAMEPAD_H +#define MICROPY_INCLUDED_GAMEPAD_H + +void gamepad_tick(void); + +#endif // MICROPY_INCLUDED_GAMEPAD_H