Skip to content

Commit 605ff91

Browse files
committed
extmod/machine_signal: Support all Pin's arguments to the constructor.
This implements the orginal idea is that Signal is a subclass of Pin, and thus can accept all the same argument as Pin, and additionally, "inverted" param. On the practical side, it allows to avoid many enclosed parenses for a typical declararion, e.g. for Zephyr: Signal(Pin(("GPIO_0", 1))). Of course, passing a Pin to Signal constructor is still supported and is the most generic form (e.g. Unix port will only support such form, as it doesn't have "builtin" Pins), what's introduces here is just practical readability optimization. "value" kwarg is treated as applying to a Signal (i.e. accounts for possible inversion).
1 parent 79ce664 commit 605ff91

File tree

4 files changed

+70
-11
lines changed

4 files changed

+70
-11
lines changed

esp8266/machine_pin.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ STATIC mp_obj_t pyb_pin_obj_init_helper(pyb_pin_obj_t *self, mp_uint_t n_args, c
287287
}
288288

289289
// constructor(id, ...)
290-
STATIC mp_obj_t pyb_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
290+
mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
291291
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
292292

293293
// get the wanted pin object
@@ -436,7 +436,7 @@ const mp_obj_type_t pyb_pin_type = {
436436
{ &mp_type_type },
437437
.name = MP_QSTR_Pin,
438438
.print = pyb_pin_print,
439-
.make_new = pyb_pin_make_new,
439+
.make_new = mp_pin_make_new,
440440
.call = pyb_pin_call,
441441
.protocol = &pin_pin_p,
442442
.locals_dict = (mp_obj_t)&pyb_pin_locals_dict,

esp8266/mpconfigport.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
#define MICROPY_PY_UZLIB (1)
7474
#define MICROPY_PY_LWIP (1)
7575
#define MICROPY_PY_MACHINE (1)
76+
#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new
7677
#define MICROPY_PY_MACHINE_PULSE (1)
7778
#define MICROPY_PY_MACHINE_I2C (1)
7879
#define MICROPY_PY_MACHINE_SPI (1)

extmod/machine_signal.c

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
#include "py/mpconfig.h"
2828
#if MICROPY_PY_MACHINE
2929

30+
#include <string.h>
31+
3032
#include "py/obj.h"
3133
#include "py/runtime.h"
3234
#include "extmod/virtpin.h"
@@ -41,20 +43,73 @@ typedef struct _machine_signal_t {
4143
} machine_signal_t;
4244

4345
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-
enum { ARG_pin, ARG_inverted };
45-
static const mp_arg_t allowed_args[] = {
46-
{ MP_QSTR_, MP_ARG_OBJ | MP_ARG_REQUIRED },
47-
{ MP_QSTR_inverted, MP_ARG_BOOL, {.u_bool = false} },
48-
};
46+
mp_obj_t pin = args[0];
47+
bool inverted = false;
48+
49+
#if defined(MICROPY_PY_MACHINE_PIN_MAKE_NEW)
50+
mp_pin_p_t *pin_p = NULL;
51+
52+
if (MP_OBJ_IS_OBJ(pin)) {
53+
mp_obj_base_t *pin_base = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);
54+
pin_p = (mp_pin_p_t*)pin_base->type->protocol;
55+
}
56+
57+
if (pin_p == NULL) {
58+
// If first argument isn't a Pin-like object, we filter out "inverted"
59+
// from keyword arguments and pass them all to the exported Pin
60+
// constructor to create one.
61+
mp_obj_t pin_args[n_args + n_kw * 2];
62+
memcpy(pin_args, args, n_args * sizeof(mp_obj_t));
63+
const mp_obj_t *src = args + n_args;
64+
mp_obj_t *dst = pin_args + n_args;
65+
mp_obj_t *sig_value = NULL;
66+
for (size_t cnt = n_kw; cnt; cnt--) {
67+
if (*src == MP_OBJ_NEW_QSTR(MP_QSTR_inverted)) {
68+
inverted = mp_obj_is_true(src[1]);
69+
n_kw--;
70+
} else {
71+
*dst++ = *src;
72+
*dst++ = src[1];
73+
}
74+
if (*src == MP_OBJ_NEW_QSTR(MP_QSTR_value)) {
75+
// Value is pertained to Signal, so we should invert
76+
// it for Pin if needed, and we should do it only when
77+
// inversion status is guaranteedly known.
78+
sig_value = dst - 1;
79+
}
80+
src += 2;
81+
}
4982

50-
mp_arg_val_t parsed_args[MP_ARRAY_SIZE(allowed_args)];
83+
if (inverted && sig_value != NULL) {
84+
*sig_value = mp_obj_is_true(*sig_value) ? MP_OBJ_NEW_SMALL_INT(0) : MP_OBJ_NEW_SMALL_INT(1);
85+
}
5186

52-
mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, parsed_args);
87+
// Here we pass NULL as a type, hoping that mp_pin_make_new()
88+
// will just ignore it as set a concrete type. If not, we'd need
89+
// to expose port's "default" pin type too.
90+
pin = MICROPY_PY_MACHINE_PIN_MAKE_NEW(NULL, n_args, n_kw, pin_args);
91+
}
92+
else
93+
#endif
94+
// Otherwise there should be 1 or 2 args
95+
{
96+
if (n_args == 1) {
97+
if (n_kw == 0) {
98+
} else if (n_kw == 1 && args[1] == MP_OBJ_NEW_QSTR(MP_QSTR_inverted)) {
99+
inverted = mp_obj_is_true(args[1]);
100+
} else {
101+
goto error;
102+
}
103+
} else {
104+
error:
105+
mp_raise_TypeError(NULL);
106+
}
107+
}
53108

54109
machine_signal_t *o = m_new_obj(machine_signal_t);
55110
o->base.type = type;
56-
o->pin = parsed_args[ARG_pin].u_obj;
57-
o->inverted = parsed_args[ARG_inverted].u_bool;
111+
o->pin = pin;
112+
o->inverted = inverted;
58113
return MP_OBJ_FROM_PTR(o);
59114
}
60115

extmod/virtpin.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,6 @@ typedef struct _mp_pin_p_t {
3838

3939
int mp_virtual_pin_read(mp_obj_t pin);
4040
void mp_virtual_pin_write(mp_obj_t pin, int value);
41+
42+
// If a port exposes a Pin object, it's constructor should be like this
43+
mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);

0 commit comments

Comments
 (0)