1 /*
2 * Copyright (C) 2015-2021 Alibaba Group Holding Limited
3 */
4
5 #include <stdio.h>
6 #include <string.h>
7
8 #include "extmod/virtpin.h"
9 #include "modmachine.h"
10 #include "mphalport.h"
11 #include "py/mphal.h"
12 #include "py/runtime.h"
13
14 #if MICROPY_PY_MACHINE
15
16 #include "aos_hal_gpio.h"
17 #include "ulog/ulog.h"
18
19 #define LOG_TAG "machine_pin"
20
21 // Used to implement a range of pull capabilities
22 #define GPIO_PULL_DOWN (1)
23 #define GPIO_PULL_UP (2)
24 #define GPIO_PULL_HOLD (4)
25 #define GPIO_AF (8)
26 #define GPIO_OD_NONE (16)
27 #define GPIO_OD_PULL_UP (32)
28
29 #define GPIO_PIN_INTR_LOLEVEL (0)
30 #define GPIO_PIN_INTR_HILEVEL (1)
31
32 typedef struct _machine_pin_obj_t {
33 mp_obj_base_t base;
34 mp_hal_pin_obj_t id;
35 gpio_irq_trigger_t trigger;
36 mp_obj_t callback;
37 } machine_pin_obj_t;
38
39 STATIC machine_pin_obj_t machine_pin_obj[PY_GPIO_NUM_MAX] = { 0 };
40
41 const mp_obj_type_t machine_pin_type;
42
machine_pins_init(void)43 void machine_pins_init(void)
44 {
45 static bool did_install = false;
46 if (!did_install) {
47 for (int i = 0; i < MP_ARRAY_SIZE(machine_pin_obj); ++i) {
48 machine_pin_obj[i].base.type = &machine_pin_type;
49 machine_pin_obj[i].id = 0;
50 machine_pin_obj[i].callback = NULL;
51 }
52 did_install = true;
53 }
54 }
55
machine_pins_deinit(void)56 void machine_pins_deinit(void)
57 {
58 for (int i = 0; i < MP_ARRAY_SIZE(machine_pin_obj); ++i) {
59 // aos_hal_gpio_disable_irq(&machine_pin_obj[i].dev);
60 }
61 }
62
machine_pin_isr_handler(void * arg)63 STATIC void machine_pin_isr_handler(void *arg)
64 {
65 machine_pin_obj_t *self = (machine_pin_obj_t *)arg;
66 mp_obj_t callback = self->callback;
67 if (callback != mp_const_none && mp_obj_is_callable(callback)) {
68 callback_to_python(callback, self);
69 }
70 }
71
machine_pin_get_id(mp_obj_t pin_in)72 mp_hal_pin_obj_t machine_pin_get_id(mp_obj_t pin_in)
73 {
74 if (mp_obj_get_type(pin_in) != &machine_pin_type) {
75 mp_raise_ValueError(MP_ERROR_TEXT("expecting a pin"));
76 }
77 machine_pin_obj_t *self = pin_in;
78 return self->id;
79 }
80
machine_pin_print(const mp_print_t * print,mp_obj_t self_in,mp_print_kind_t kind)81 STATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind)
82 {
83 machine_pin_obj_t *self = self_in;
84 mp_printf(print, "Pin(%u)", self->id);
85 }
86
87 // pin.init(mode, pull=None, *, value)
machine_pin_obj_init_helper(const machine_pin_obj_t * self,size_t n_args,const mp_obj_t * pos_args,mp_map_t * kw_args)88 STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args,
89 mp_map_t *kw_args)
90 {
91 enum {
92 ARG_mode,
93 ARG_pull,
94 ARG_value
95 };
96 static const mp_arg_t allowed_args[] = {
97 { MP_QSTR_mode, MP_ARG_OBJ, { .u_obj = mp_const_none } },
98 { MP_QSTR_pull, MP_ARG_OBJ, { .u_obj = MP_OBJ_NEW_SMALL_INT(-1) } },
99 { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } },
100 };
101
102 // parse args
103 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
104 mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
105
106 // set initial value (do this before configuring mode/pull)
107 bool pin_initial_value = false;
108 if (args[ARG_value].u_obj != MP_OBJ_NULL) {
109 pin_initial_value = mp_obj_is_true(args[ARG_value].u_obj);
110 }
111
112 // configure mode
113 mp_int_t pin_io_mode = GPIO_INPUT;
114 if (args[ARG_mode].u_obj != mp_const_none) {
115 pin_io_mode = mp_obj_get_int(args[ARG_mode].u_obj);
116 }
117
118 // configure pull
119 mp_int_t pin_pull_mode = GPIO_PULL_UP;
120 if (args[ARG_pull].u_obj != MP_OBJ_NEW_SMALL_INT(-1)) {
121 int mode = 0;
122 if (args[ARG_pull].u_obj != mp_const_none) {
123 mode = mp_obj_get_int(args[ARG_pull].u_obj);
124 }
125 }
126
127 gpio_config_t config;
128 if (pin_io_mode == GPIO_INPUT) {
129 if (pin_pull_mode == GPIO_PULL_UP)
130 config = INPUT_PULL_UP;
131 else if (pin_pull_mode == GPIO_PULL_DOWN)
132 config = INPUT_PULL_DOWN;
133 else
134 config = INPUT_HIGH_IMPEDANCE;
135 } else if (pin_io_mode == GPIO_OUTPUT_PP) {
136 if (pin_pull_mode == GPIO_AF)
137 config = OUTPUT_PUSH_PULL_AF;
138 else
139 config = OUTPUT_PUSH_PULL;
140 } else if (pin_io_mode == GPIO_OUTPUT_OD) {
141 if (pin_pull_mode == GPIO_OD_NONE)
142 config = OUTPUT_OPEN_DRAIN_NO_PULL;
143 else if (pin_pull_mode == GPIO_OD_PULL_UP)
144 config = OUTPUT_OPEN_DRAIN_PULL_UP;
145 else if (pin_pull_mode == GPIO_AF)
146 config = OUTPUT_OPEN_DRAIN_AF;
147 }
148
149 mp_int_t ret = mp_hal_pin_config_set(self->id, config);
150 if (ret == 0) {
151 if (pin_io_mode != GPIO_INPUT) {
152 mp_hal_pin_write(self->id, pin_initial_value);
153 }
154 }
155 return MP_OBJ_NEW_SMALL_INT(ret);
156 }
157
158 // constructor(id, ...)
mp_pin_make_new(const mp_obj_type_t * type,size_t n_args,size_t n_kw,const mp_obj_t * args)159 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)
160 {
161 mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
162
163 // get the wanted pin object
164 int wanted_pin = mp_obj_get_int(args[0]);
165 machine_pin_obj_t *self = NULL;
166 if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(machine_pin_obj)) {
167 self = (machine_pin_obj_t *)&machine_pin_obj[wanted_pin];
168 }
169 if (self->base.type == NULL) {
170 self->base.type = &machine_pin_type;
171 self->id = wanted_pin;
172 self->callback = mp_const_none;
173 }
174
175 if (n_args > 1 || n_kw > 0) {
176 // pin mode given, so configure this GPIO
177 mp_map_t kw_args;
178 mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
179 machine_pin_obj_init_helper(self, n_args - 1, args + 1, &kw_args);
180 }
181
182 return MP_OBJ_FROM_PTR(self);
183 }
184
185 // fast method for getting/setting pin value
machine_pin_call(mp_obj_t self_in,size_t n_args,size_t n_kw,const mp_obj_t * args)186 STATIC mp_obj_t machine_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args)
187 {
188 mp_arg_check_num(n_args, n_kw, 0, 1, false);
189 machine_pin_obj_t *self = self_in;
190 if (n_args == 0) {
191 // get pin
192 return MP_OBJ_NEW_SMALL_INT(mp_hal_pin_read(self->id));
193 } else {
194 // set pin
195 mp_hal_pin_write(self->id, mp_obj_is_true(args[0]));
196 return mp_const_none;
197 }
198 }
199
200 // pin.init(mode, pull)
machine_pin_init(size_t n_args,const mp_obj_t * args,mp_map_t * kw_args)201 STATIC mp_obj_t machine_pin_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args)
202 {
203 return machine_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args);
204 }
205 MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_init);
206
207 // pin.value([value])
machine_pin_value(size_t n_args,const mp_obj_t * args)208 STATIC mp_obj_t machine_pin_value(size_t n_args, const mp_obj_t *args)
209 {
210 return machine_pin_call(args[0], n_args - 1, 0, args + 1);
211 }
212 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_pin_value);
213
214 // pin.off()
machine_pin_off(mp_obj_t self_in)215 STATIC mp_obj_t machine_pin_off(mp_obj_t self_in)
216 {
217 machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
218 mp_hal_pin_write(self->id, 0);
219 return mp_const_none;
220 }
221 STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_off_obj, machine_pin_off);
222
223 // pin.on()
machine_pin_on(mp_obj_t self_in)224 STATIC mp_obj_t machine_pin_on(mp_obj_t self_in)
225 {
226 machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
227 mp_hal_pin_write(self->id, 1);
228 return mp_const_none;
229 }
230 STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_on_obj, machine_pin_on);
231
232 // pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING)
machine_pin_irq(size_t n_args,const mp_obj_t * pos_args,mp_map_t * kw_args)233 STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
234 {
235 enum {
236 ARG_handler,
237 ARG_trigger,
238 ARG_wake
239 };
240 static const mp_arg_t allowed_args[] = {
241 { MP_QSTR_handler, MP_ARG_OBJ, { .u_obj = mp_const_none } },
242 { MP_QSTR_trigger, MP_ARG_INT, { .u_int = IRQ_TRIGGER_RISING_EDGE | IRQ_TRIGGER_FALLING_EDGE } },
243 { MP_QSTR_wake, MP_ARG_OBJ, { .u_obj = mp_const_none } },
244 };
245 machine_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
246 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
247 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
248
249 if (n_args > 1 || kw_args->used != 0) {
250 // configure irq
251 mp_obj_t handler = args[ARG_handler].u_obj;
252 mp_uint_t trigger = args[ARG_trigger].u_int;
253 mp_obj_t wake_obj = args[ARG_wake].u_obj;
254
255 if ((trigger == GPIO_PIN_INTR_LOLEVEL || trigger == GPIO_PIN_INTR_HILEVEL) && wake_obj != mp_const_none) {
256 mp_int_t wake;
257 if (mp_obj_get_int_maybe(wake_obj, &wake)) {
258 if (wake < 2 || wake > 7) {
259 mp_raise_ValueError(MP_ERROR_TEXT("bad wake value"));
260 }
261 } else {
262 mp_raise_ValueError(MP_ERROR_TEXT("bad wake value"));
263 }
264 } else {
265 if (handler == mp_const_none) {
266 handler = MP_OBJ_NULL;
267 trigger = 0;
268 }
269 self->callback = handler;
270 self->trigger = trigger;
271
272 gpio_dev_t dev = { 0 };
273 dev.port = self->id;
274 dev.config = mp_hal_pin_config_get(self->id);
275
276 aos_hal_gpio_enable_irq(&dev, trigger, machine_pin_isr_handler, (void *)self);
277 }
278 }
279
280 // return the irq object
281 return MP_OBJ_FROM_PTR(&machine_pin_obj[self->id]);
282 }
283 STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_irq_obj, 1, machine_pin_irq);
284
machine_pin_irq_enable(mp_obj_t self_in)285 STATIC mp_obj_t machine_pin_irq_enable(mp_obj_t self_in)
286 {
287 machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
288 if (self->callback == MP_OBJ_NULL) {
289 mp_raise_ValueError(MP_ERROR_TEXT("irq cabllback null"));
290 }
291
292 gpio_dev_t dev = { 0 };
293 dev.port = self->id;
294 dev.config = mp_hal_pin_config_get(self->id);
295 aos_hal_gpio_enable_irq(&dev, self->trigger, machine_pin_isr_handler, (void *)self);
296 return mp_const_none;
297 }
298 STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_irq_enable_obj, machine_pin_irq_enable);
299
machine_pin_irq_disable(mp_obj_t self_in)300 STATIC mp_obj_t machine_pin_irq_disable(mp_obj_t self_in)
301 {
302 machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
303 gpio_dev_t dev = { 0 };
304 dev.port = self->id;
305 dev.config = mp_hal_pin_config_get(self->id);
306 aos_hal_gpio_disable_irq(&dev);
307 return mp_const_none;
308 }
309 STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_irq_disable_obj, machine_pin_irq_disable);
310
machine_pin_deinit(mp_obj_t self_in)311 STATIC mp_obj_t machine_pin_deinit(mp_obj_t self_in)
312 {
313 machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
314 gpio_dev_t dev = { 0 };
315 dev.port = self->id;
316 dev.config = mp_hal_pin_config_get(self->id);
317
318 mp_int_t ret = -1;
319 if (mp_const_none != self->callback) {
320 ret = aos_hal_gpio_disable_irq(&dev);
321 ret = aos_hal_gpio_clear_irq(&dev);
322 }
323
324 ret = aos_hal_gpio_finalize(&dev);
325
326 self->callback = mp_const_none;
327 self->id = 0;
328 self->trigger = 0;
329
330 return MP_OBJ_NEW_SMALL_INT(ret);
331 }
332 STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_deinit_obj, machine_pin_deinit);
333
334 STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = {
335 // instance methods
336 { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pin_init_obj) },
337 { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_pin_value_obj) },
338 { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&machine_pin_off_obj) },
339 { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&machine_pin_on_obj) },
340 { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_pin_irq_obj) },
341 { MP_ROM_QSTR(MP_QSTR_enable), MP_ROM_PTR(&machine_pin_irq_enable_obj) },
342 { MP_ROM_QSTR(MP_QSTR_disable), MP_ROM_PTR(&machine_pin_irq_disable_obj) },
343 { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_pin_deinit_obj) },
344
345 // class constants
346 { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_INPUT) },
347 { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_OUTPUT_PP) },
348 { MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(GPIO_OUTPUT_OD) },
349 { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PULL_UP) },
350 { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULL_DOWN) },
351 { MP_ROM_QSTR(MP_QSTR_PULL_HOLD), MP_ROM_INT(GPIO_PULL_HOLD) },
352 { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(IRQ_TRIGGER_RISING_EDGE) },
353 { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(IRQ_TRIGGER_FALLING_EDGE) },
354 { MP_ROM_QSTR(MP_QSTR_WAKE_LOW), MP_ROM_INT(GPIO_PIN_INTR_LOLEVEL) },
355 { MP_ROM_QSTR(MP_QSTR_WAKE_HIGH), MP_ROM_INT(GPIO_PIN_INTR_HILEVEL) },
356 };
357 STATIC MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table);
358
pin_ioctl(mp_obj_t self_in,mp_uint_t request,uintptr_t arg,int * errcode)359 STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode)
360 {
361 (void)errcode;
362 machine_pin_obj_t *self = self_in;
363 mp_uint_t ret = 100;
364 switch (request) {
365 case MP_PIN_READ:
366 ret = mp_hal_pin_read(self->id);
367 break;
368
369 case MP_PIN_WRITE:
370 ret = mp_hal_pin_write(self->id, arg);
371 break;
372 }
373
374 return ret;
375 }
376
377 STATIC const mp_pin_p_t pin_pin_p = {
378 .ioctl = pin_ioctl,
379 };
380
381 const mp_obj_type_t machine_pin_type = {
382 { &mp_type_type },
383 .name = MP_QSTR_Pin,
384 .print = machine_pin_print,
385 .make_new = mp_pin_make_new,
386 .call = machine_pin_call,
387 .protocol = &pin_pin_p,
388 .locals_dict = (mp_obj_t)&machine_pin_locals_dict,
389 };
390
391 #endif