Branch data Line data Source code
1 : : /*
2 : : * This file is part of the MicroPython project, http://micropython.org/
3 : : *
4 : : * The MIT License (MIT)
5 : : *
6 : : * Copyright (c) 2017 Paul Sokolovsky
7 : : *
8 : : * Permission is hereby granted, free of charge, to any person obtaining a copy
9 : : * of this software and associated documentation files (the "Software"), to deal
10 : : * in the Software without restriction, including without limitation the rights
11 : : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : : * copies of the Software, and to permit persons to whom the Software is
13 : : * furnished to do so, subject to the following conditions:
14 : : *
15 : : * The above copyright notice and this permission notice shall be included in
16 : : * all copies or substantial portions of the Software.
17 : : *
18 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 : : * THE SOFTWARE.
25 : : */
26 : :
27 : : #include <string.h>
28 : : #include "py/runtime.h"
29 : :
30 : : #if MICROPY_PY_MACHINE_SIGNAL
31 : :
32 : : #include "extmod/modmachine.h"
33 : : #include "extmod/virtpin.h"
34 : :
35 : : // Signal class
36 : :
37 : : typedef struct _machine_signal_t {
38 : : mp_obj_base_t base;
39 : : mp_obj_t pin;
40 : : bool invert;
41 : : } machine_signal_t;
42 : :
43 : 8 : 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) {
44 : 8 : mp_obj_t pin;
45 : 8 : bool invert = false;
46 : :
47 : : #if defined(MICROPY_PY_MACHINE_PIN_MAKE_NEW)
48 : : mp_pin_p_t *pin_p = NULL;
49 : :
50 : : if (n_args > 0 && mp_obj_is_obj(args[0])) {
51 : : mp_obj_base_t *pin_base = (mp_obj_base_t *)MP_OBJ_TO_PTR(args[0]);
52 : : pin_p = (mp_pin_p_t *)MP_OBJ_TYPE_GET_SLOT_OR_NULL(pin_base->type, protocol);
53 : : }
54 : :
55 : : if (pin_p == NULL) {
56 : : // If first argument isn't a Pin-like object, we filter out "invert"
57 : : // from keyword arguments and pass them all to the exported Pin
58 : : // constructor to create one.
59 : : mp_obj_t *pin_args = mp_local_alloc((n_args + n_kw * 2) * sizeof(mp_obj_t));
60 : : memcpy(pin_args, args, n_args * sizeof(mp_obj_t));
61 : : const mp_obj_t *src = args + n_args;
62 : : mp_obj_t *dst = pin_args + n_args;
63 : : mp_obj_t *sig_value = NULL;
64 : : for (size_t cnt = n_kw; cnt; cnt--) {
65 : : if (*src == MP_OBJ_NEW_QSTR(MP_QSTR_invert)) {
66 : : invert = mp_obj_is_true(src[1]);
67 : : n_kw--;
68 : : } else {
69 : : *dst++ = *src;
70 : : *dst++ = src[1];
71 : : }
72 : : if (*src == MP_OBJ_NEW_QSTR(MP_QSTR_value)) {
73 : : // Value is pertained to Signal, so we should invert
74 : : // it for Pin if needed, and we should do it only when
75 : : // inversion status is guaranteedly known.
76 : : sig_value = dst - 1;
77 : : }
78 : : src += 2;
79 : : }
80 : :
81 : : if (invert && sig_value != NULL) {
82 : : *sig_value = mp_obj_is_true(*sig_value) ? MP_OBJ_NEW_SMALL_INT(0) : MP_OBJ_NEW_SMALL_INT(1);
83 : : }
84 : :
85 : : // Here we pass NULL as a type, hoping that mp_pin_make_new()
86 : : // will just ignore it as set a concrete type. If not, we'd need
87 : : // to expose port's "default" pin type too.
88 : : pin = MICROPY_PY_MACHINE_PIN_MAKE_NEW(NULL, n_args, n_kw, pin_args);
89 : :
90 : : mp_local_free(pin_args);
91 : : } else
92 : : #endif
93 : : // Otherwise there should be 1 or 2 args
94 : : {
95 [ - + ]: 8 : if (n_args == 1) {
96 : 8 : pin = args[0];
97 [ + + ]: 8 : if (n_kw == 0) {
98 [ + - + - ]: 2 : } else if (n_kw == 1 && args[1] == MP_OBJ_NEW_QSTR(MP_QSTR_invert)) {
99 : 2 : invert = mp_obj_is_true(args[2]);
100 : : } else {
101 : 0 : goto error;
102 : : }
103 : : } else {
104 : 0 : error:
105 : 0 : mp_raise_TypeError(NULL);
106 : : }
107 : : }
108 : :
109 : 8 : machine_signal_t *o = mp_obj_malloc(machine_signal_t, type);
110 : 8 : o->pin = pin;
111 : 8 : o->invert = invert;
112 : 8 : return MP_OBJ_FROM_PTR(o);
113 : : }
114 : :
115 : 20 : static mp_uint_t signal_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
116 : 20 : (void)errcode;
117 : 20 : machine_signal_t *self = MP_OBJ_TO_PTR(self_in);
118 : :
119 [ + + - ]: 20 : switch (request) {
120 : 12 : case MP_PIN_READ: {
121 : 12 : return mp_virtual_pin_read(self->pin) ^ self->invert;
122 : : }
123 : 8 : case MP_PIN_WRITE: {
124 : 8 : mp_virtual_pin_write(self->pin, arg ^ self->invert);
125 : 8 : return 0;
126 : : }
127 : : }
128 : : return -1;
129 : : }
130 : :
131 : : // fast method for getting/setting signal value
132 : 16 : static mp_obj_t signal_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
133 : 16 : mp_arg_check_num(n_args, n_kw, 0, 1, false);
134 [ + + ]: 16 : if (n_args == 0) {
135 : : // get pin
136 : 12 : return MP_OBJ_NEW_SMALL_INT(mp_virtual_pin_read(self_in));
137 : : } else {
138 : : // set pin
139 : 4 : mp_virtual_pin_write(self_in, mp_obj_is_true(args[0]));
140 : 4 : return mp_const_none;
141 : : }
142 : : }
143 : :
144 : 12 : static mp_obj_t signal_value(size_t n_args, const mp_obj_t *args) {
145 : 12 : return signal_call(args[0], n_args - 1, 0, args + 1);
146 : : }
147 : : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(signal_value_obj, 1, 2, signal_value);
148 : :
149 : 2 : static mp_obj_t signal_on(mp_obj_t self_in) {
150 : 2 : mp_virtual_pin_write(self_in, 1);
151 : 2 : return mp_const_none;
152 : : }
153 : : static MP_DEFINE_CONST_FUN_OBJ_1(signal_on_obj, signal_on);
154 : :
155 : 2 : static mp_obj_t signal_off(mp_obj_t self_in) {
156 : 2 : mp_virtual_pin_write(self_in, 0);
157 : 2 : return mp_const_none;
158 : : }
159 : : static MP_DEFINE_CONST_FUN_OBJ_1(signal_off_obj, signal_off);
160 : :
161 : : static const mp_rom_map_elem_t signal_locals_dict_table[] = {
162 : : { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&signal_value_obj) },
163 : : { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&signal_on_obj) },
164 : : { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&signal_off_obj) },
165 : : };
166 : :
167 : : static MP_DEFINE_CONST_DICT(signal_locals_dict, signal_locals_dict_table);
168 : :
169 : : static const mp_pin_p_t signal_pin_p = {
170 : : .ioctl = signal_ioctl,
171 : : };
172 : :
173 : : MP_DEFINE_CONST_OBJ_TYPE(
174 : : machine_signal_type,
175 : : MP_QSTR_Signal,
176 : : MP_TYPE_FLAG_NONE,
177 : : make_new, signal_make_new,
178 : : call, signal_call,
179 : : protocol, &signal_pin_p,
180 : : locals_dict, &signal_locals_dict
181 : : );
182 : :
183 : : #endif // MICROPY_PY_MACHINE_SIGNAL
|