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