Skip to content
Snippets Groups Projects
Select Git revision
  • cd6b115815f8b618b27e2f49a7611de95983f6f4
  • master default protected
2 results

machine_signal.c

Blame
  • machine_signal.c 6.08 KiB
    /*
     * This file is part of the MicroPython project, http://micropython.org/
     *
     * The MIT License (MIT)
     *
     * Copyright (c) 2017 Paul Sokolovsky
     *
     * 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/mpconfig.h"
    #if MICROPY_PY_MACHINE
    
    #include <string.h>
    
    #include "py/obj.h"
    #include "py/runtime.h"
    #include "extmod/virtpin.h"
    #include "extmod/machine_signal.h"
    
    // Signal class
    
    typedef struct _machine_signal_t {
        mp_obj_base_t base;
        mp_obj_t pin;
        bool invert;
    } machine_signal_t;
    
    STATIC mp_obj_t signal_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
        mp_obj_t pin;
        bool invert = false;
    
        #if defined(MICROPY_PY_MACHINE_PIN_MAKE_NEW)
        mp_pin_p_t *pin_p = NULL;
    
        if (n_args > 0 && mp_obj_is_obj(args[0])) {
            mp_obj_base_t *pin_base = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);
            pin_p = (mp_pin_p_t*)pin_base->type->protocol;
        }
    
        if (pin_p == NULL) {
            // If first argument isn't a Pin-like object, we filter out "invert"
            // from keyword arguments and pass them all to the exported Pin
            // constructor to create one.
            mp_obj_t *pin_args = mp_local_alloc((n_args + n_kw * 2) * sizeof(mp_obj_t));
            memcpy(pin_args, args, n_args * sizeof(mp_obj_t));
            const mp_obj_t *src = args + n_args;
            mp_obj_t *dst = pin_args + n_args;
            mp_obj_t *sig_value = NULL;
            for (size_t cnt = n_kw; cnt; cnt--) {
                if (*src == MP_OBJ_NEW_QSTR(MP_QSTR_invert)) {
                    invert = mp_obj_is_true(src[1]);
                    n_kw--;
                } else {
                    *dst++ = *src;
                    *dst++ = src[1];
                }
                if (*src == MP_OBJ_NEW_QSTR(MP_QSTR_value)) {
                    // Value is pertained to Signal, so we should invert
                    // it for Pin if needed, and we should do it only when
                    // inversion status is guaranteedly known.
                    sig_value = dst - 1;
                }
                src += 2;
            }
    
            if (invert && sig_value != NULL) {
                *sig_value = mp_obj_is_true(*sig_value) ? MP_OBJ_NEW_SMALL_INT(0) : MP_OBJ_NEW_SMALL_INT(1);
            }
    
            // Here we pass NULL as a type, hoping that mp_pin_make_new()
            // will just ignore it as set a concrete type. If not, we'd need
            // to expose port's "default" pin type too.
            pin = MICROPY_PY_MACHINE_PIN_MAKE_NEW(NULL, n_args, n_kw, pin_args);
    
            mp_local_free(pin_args);
        }
        else
        #endif
        // Otherwise there should be 1 or 2 args
        {
            if (n_args == 1) {
                pin = args[0];
                if (n_kw == 0) {
                } else if (n_kw == 1 && args[1] == MP_OBJ_NEW_QSTR(MP_QSTR_invert)) {
                    invert = mp_obj_is_true(args[2]);
                } else {
                    goto error;
                }
            } else {
            error:
                mp_raise_TypeError(NULL);
            }
        }
    
        machine_signal_t *o = m_new_obj(machine_signal_t);
        o->base.type = type;
        o->pin = pin;
        o->invert = invert;
        return MP_OBJ_FROM_PTR(o);
    }
    
    STATIC mp_uint_t signal_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
        (void)errcode;
        machine_signal_t *self = MP_OBJ_TO_PTR(self_in);
    
        switch (request) {
            case MP_PIN_READ: {
                return mp_virtual_pin_read(self->pin) ^ self->invert;
            }
            case MP_PIN_WRITE: {
                mp_virtual_pin_write(self->pin, arg ^ self->invert);
                return 0;
            }
        }
        return -1;
    }
    
    // fast method for getting/setting signal value
    STATIC mp_obj_t signal_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
        mp_arg_check_num(n_args, n_kw, 0, 1, false);
        if (n_args == 0) {
            // get pin
            return MP_OBJ_NEW_SMALL_INT(mp_virtual_pin_read(self_in));
        } else {
            // set pin
            mp_virtual_pin_write(self_in, mp_obj_is_true(args[0]));
            return mp_const_none;
        }
    }
    
    STATIC mp_obj_t signal_value(size_t n_args, const mp_obj_t *args) {
        return signal_call(args[0], n_args - 1, 0, args + 1);
    }
    STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(signal_value_obj, 1, 2, signal_value);
    
    STATIC mp_obj_t signal_on(mp_obj_t self_in) {
        mp_virtual_pin_write(self_in, 1);
        return mp_const_none;
    }
    STATIC MP_DEFINE_CONST_FUN_OBJ_1(signal_on_obj, signal_on);
    
    STATIC mp_obj_t signal_off(mp_obj_t self_in) {
        mp_virtual_pin_write(self_in, 0);
        return mp_const_none;
    }
    STATIC MP_DEFINE_CONST_FUN_OBJ_1(signal_off_obj, signal_off);
    
    STATIC const mp_rom_map_elem_t signal_locals_dict_table[] = {
        { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&signal_value_obj) },
        { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&signal_on_obj) },
        { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&signal_off_obj) },
    };
    
    STATIC MP_DEFINE_CONST_DICT(signal_locals_dict, signal_locals_dict_table);
    
    STATIC const mp_pin_p_t signal_pin_p = {
        .ioctl = signal_ioctl,
    };
    
    const mp_obj_type_t machine_signal_type = {
        { &mp_type_type },
        .name = MP_QSTR_Signal,
        .make_new = signal_make_new,
        .call = signal_call,
        .protocol = &signal_pin_p,
        .locals_dict = (void*)&signal_locals_dict,
    };
    
    #endif // MICROPY_PY_MACHINE