1 /*
2  * This file is part of the MicroPython project, http://micropython.org/
3  *
4  * Development of the code in this file was sponsored by Microbric Pty Ltd
5  *
6  * The MIT License (MIT)
7  *
8  * Copyright (c) 2016 Damien P. George
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a copy
11  * of this software and associated documentation files (the "Software"), to deal
12  * in the Software without restriction, including without limitation the rights
13  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14  * copies of the Software, and to permit persons to whom the Software is
15  * furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included in
18  * all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26  * THE SOFTWARE.
27  */
28 
29 #include <stdio.h>
30 #include <string.h>
31 
32 #include "py/runtime.h"
33 #include "py/mphal.h"
34 #include "mphalport.h"
35 #include "modmachine.h"
36 #include "extmod/virtpin.h"
37 
38 #if MICROPY_PY_MACHINE
39 
40 #include "ulog/ulog.h"
41 #include "aos_hal_gpio.h"
42 
43 #define LOG_TAG "machine_pin"
44 
45 // Used to implement a range of pull capabilities
46 #define GPIO_PULL_DOWN      (1)
47 #define GPIO_PULL_UP        (2)
48 #define GPIO_PULL_HOLD      (4)
49 #define GPIO_AF             (8)
50 
51 #define GPIO_OD_NONE        (16)
52 #define GPIO_OD_PULL_UP     (32)
53 
54 #define GPIO_PIN_INTR_LOLEVEL (0)
55 #define GPIO_PIN_INTR_HILEVEL (1)
56 
57 typedef struct _machine_pin_obj_t {
58     mp_obj_base_t base;
59     mp_hal_pin_obj_t id;
60     gpio_irq_trigger_t trigger;
61     mp_obj_t callback;
62 } machine_pin_obj_t;
63 
64 STATIC machine_pin_obj_t machine_pin_obj[PY_GPIO_NUM_MAX] = {0};
65 
66 const mp_obj_type_t machine_pin_type;
67 
machine_pins_init(void)68 void machine_pins_init(void) {
69     static bool did_install = false;
70     if (!did_install) {
71         for(int i = 0; i < MP_ARRAY_SIZE(machine_pin_obj); ++i) {
72             machine_pin_obj[i].base.type = &machine_pin_type;
73             machine_pin_obj[i].id = 0;
74             machine_pin_obj[i].callback = NULL;
75         }
76         did_install = true;
77     }
78 }
79 
machine_pins_deinit(void)80 void machine_pins_deinit(void) {
81     for (int i = 0; i < MP_ARRAY_SIZE(machine_pin_obj); ++i) {
82         // aos_hal_gpio_disable_irq(&machine_pin_obj[i].dev);
83     }
84 }
85 
machine_pin_isr_handler(void * arg)86 STATIC void machine_pin_isr_handler(void *arg) {
87     machine_pin_obj_t *self = arg;
88     if (self->callback != mp_const_none) {
89         callback_to_python(self->callback, self);
90     }
91 }
92 
machine_pin_get_id(mp_obj_t pin_in)93 mp_hal_pin_obj_t machine_pin_get_id(mp_obj_t pin_in) {
94     if (mp_obj_get_type(pin_in) != &machine_pin_type) {
95         mp_raise_ValueError(MP_ERROR_TEXT("expecting a pin"));
96     }
97     machine_pin_obj_t *self = pin_in;
98     return self->id;
99 }
100 
machine_pin_print(const mp_print_t * print,mp_obj_t self_in,mp_print_kind_t kind)101 STATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
102     machine_pin_obj_t *self = self_in;
103     mp_printf(print, "Pin(%u)", self->id);
104 }
105 
106 // 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)107 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, mp_map_t *kw_args) {
108     enum { ARG_mode, ARG_pull, ARG_value };
109     static const mp_arg_t allowed_args[] = {
110         { MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = mp_const_none}},
111         { MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(-1)}},
112         { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
113     };
114 
115     // parse args
116     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
117     mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
118 
119     // set initial value (do this before configuring mode/pull)
120     bool pin_initial_value = false;
121     if (args[ARG_value].u_obj != MP_OBJ_NULL) {
122         pin_initial_value = mp_obj_is_true(args[ARG_value].u_obj);
123     }
124 
125     // configure mode
126     mp_int_t pin_io_mode = GPIO_INPUT;
127     if (args[ARG_mode].u_obj != mp_const_none) {
128         pin_io_mode = mp_obj_get_int(args[ARG_mode].u_obj);
129     }
130 
131     // configure pull
132      mp_int_t pin_pull_mode = GPIO_PULL_UP;
133     if (args[ARG_pull].u_obj != MP_OBJ_NEW_SMALL_INT(-1)) {
134         int mode = 0;
135         if (args[ARG_pull].u_obj != mp_const_none) {
136             mode = mp_obj_get_int(args[ARG_pull].u_obj);
137         }
138     }
139 
140     gpio_config_t config;
141     if(pin_io_mode == GPIO_INPUT) {
142         if(pin_pull_mode == GPIO_PULL_UP)
143             config = INPUT_PULL_UP;
144         else if(pin_pull_mode == GPIO_PULL_DOWN)
145             config = INPUT_PULL_DOWN;
146         else
147             config = INPUT_HIGH_IMPEDANCE;
148     } else if(pin_io_mode == GPIO_OUTPUT_PP) {
149         if(pin_pull_mode == GPIO_AF)
150             config = OUTPUT_PUSH_PULL_AF;
151         else
152             config = OUTPUT_PUSH_PULL;
153     } else if(pin_io_mode == GPIO_OUTPUT_OD) {
154         if(pin_pull_mode == GPIO_OD_NONE)
155             config = OUTPUT_OPEN_DRAIN_NO_PULL;
156         else if(pin_pull_mode == GPIO_OD_PULL_UP)
157             config = OUTPUT_OPEN_DRAIN_PULL_UP;
158         else if(pin_pull_mode == GPIO_AF)
159             config = OUTPUT_OPEN_DRAIN_AF;
160     }
161 
162     int32_t ret = mp_hal_pin_config_set(self->id, config);
163     if(ret == 0) {
164         if(pin_io_mode != GPIO_INPUT) {
165             mp_hal_pin_write(self->id, pin_initial_value);
166         }
167     }
168     return MP_OBJ_NEW_SMALL_INT(ret);
169 }
170 
171 // 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)172 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) {
173     mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
174 
175     // get the wanted pin object
176     int wanted_pin = mp_obj_get_int(args[0]);
177     machine_pin_obj_t *self = NULL;
178     if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(machine_pin_obj)) {
179         self = (machine_pin_obj_t *)&machine_pin_obj[wanted_pin];
180     }
181     if (self->base.type == NULL) {
182         self->base.type = &machine_pin_type;
183         self->id = wanted_pin;
184         self->callback = NULL;
185     }
186 
187     if (n_args > 1 || n_kw > 0) {
188         // pin mode given, so configure this GPIO
189         mp_map_t kw_args;
190         mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
191         machine_pin_obj_init_helper(self, n_args - 1, args + 1, &kw_args);
192     }
193 
194     return MP_OBJ_FROM_PTR(self);
195 }
196 
197 // 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)198 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) {
199     mp_arg_check_num(n_args, n_kw, 0, 1, false);
200     machine_pin_obj_t *self = self_in;
201     if (n_args == 0) {
202         // get pin
203         return MP_OBJ_NEW_SMALL_INT(mp_hal_pin_read(self->id));
204     } else {
205         // set pin
206         mp_hal_pin_write(self->id, mp_obj_is_true(args[0]));
207         return mp_const_none;
208     }
209 }
210 
211 // pin.init(mode, pull)
machine_pin_obj_init(size_t n_args,const mp_obj_t * args,mp_map_t * kw_args)212 STATIC mp_obj_t machine_pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
213     return machine_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args);
214 }
215 MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_obj_init);
216 
217 // pin.value([value])
machine_pin_value(size_t n_args,const mp_obj_t * args)218 STATIC mp_obj_t machine_pin_value(size_t n_args, const mp_obj_t *args) {
219     return machine_pin_call(args[0], n_args - 1, 0, args + 1);
220 }
221 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_pin_value);
222 
223 // pin.off()
machine_pin_off(mp_obj_t self_in)224 STATIC mp_obj_t machine_pin_off(mp_obj_t self_in) {
225     machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
226     mp_hal_pin_write(self->id, 0);
227     return mp_const_none;
228 }
229 STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_off_obj, machine_pin_off);
230 
231 // pin.on()
machine_pin_on(mp_obj_t self_in)232 STATIC mp_obj_t machine_pin_on(mp_obj_t self_in) {
233     machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
234     mp_hal_pin_write(self->id, 1);
235     return mp_const_none;
236 }
237 STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_on_obj, machine_pin_on);
238 
239 // 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)240 STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
241     enum { ARG_handler, ARG_trigger, ARG_wake };
242     static const mp_arg_t allowed_args[] = {
243         { MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} },
244         { MP_QSTR_trigger, MP_ARG_INT, {.u_int = IRQ_TRIGGER_RISING_EDGE | IRQ_TRIGGER_FALLING_EDGE} },
245         { MP_QSTR_wake, MP_ARG_OBJ, {.u_obj = mp_const_none} },
246     };
247     machine_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
248     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
249     mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
250 
251     if (n_args > 1 || kw_args->used != 0) {
252         // configure irq
253         mp_obj_t handler = args[ARG_handler].u_obj;
254         uint32_t trigger = args[ARG_trigger].u_int;
255         mp_obj_t wake_obj = args[ARG_wake].u_obj;
256 
257         if ((trigger == GPIO_PIN_INTR_LOLEVEL || trigger == GPIO_PIN_INTR_HILEVEL) && wake_obj != mp_const_none) {
258             mp_int_t wake;
259             if (mp_obj_get_int_maybe(wake_obj, &wake)) {
260                 if (wake < 2 || wake > 7) {
261                     mp_raise_ValueError(MP_ERROR_TEXT("bad wake value"));
262                 }
263             } else {
264                 mp_raise_ValueError(MP_ERROR_TEXT("bad wake value"));
265             }
266         } else {
267             if (handler == mp_const_none) {
268                 handler = MP_OBJ_NULL;
269                 trigger = 0;
270             }
271             self->callback = handler;
272             self->trigger = trigger;
273 
274             gpio_dev_t dev = {0};
275             dev.port = self->id;
276             dev.config = mp_hal_pin_config_get(self->id);
277 
278             aos_hal_gpio_enable_irq(&dev, trigger, machine_pin_isr_handler, (void *)self);
279         }
280     }
281 
282     // return the irq object
283     return MP_OBJ_FROM_PTR(&machine_pin_obj[self->id]);
284 }
285 STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_irq_obj, 1, machine_pin_irq);
286 
machine_pin_irq_enable(mp_obj_t self_in)287 STATIC mp_obj_t machine_pin_irq_enable(mp_obj_t self_in) {
288     machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
289     if(self->callback == MP_OBJ_NULL) {
290         mp_raise_ValueError(MP_ERROR_TEXT("irq cabllback null"));
291     }
292 
293     gpio_dev_t dev = {0};
294     dev.port = self->id;
295     dev.config = mp_hal_pin_config_get(self->id);
296     aos_hal_gpio_enable_irq(&dev, self->trigger, machine_pin_isr_handler, (void *)self);
297     return mp_const_none;
298 }
299 STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_irq_enable_obj, machine_pin_irq_enable);
300 
machine_pin_irq_disable(mp_obj_t self_in)301 STATIC mp_obj_t machine_pin_irq_disable(mp_obj_t self_in) {
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 
311 STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = {
312     // instance methods
313     { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pin_init_obj) },
314     { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_pin_value_obj) },
315     { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&machine_pin_off_obj) },
316     { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&machine_pin_on_obj) },
317     { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_pin_irq_obj) },
318     { MP_ROM_QSTR(MP_QSTR_enable), MP_ROM_PTR(&machine_pin_irq_enable_obj) },
319     { MP_ROM_QSTR(MP_QSTR_disable), MP_ROM_PTR(&machine_pin_irq_disable_obj) },
320 
321     // class constants
322     { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_INPUT) },
323     { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_OUTPUT_PP) },
324     { MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(GPIO_OUTPUT_OD) },
325     { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PULL_UP) },
326     { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULL_DOWN) },
327     { MP_ROM_QSTR(MP_QSTR_PULL_HOLD), MP_ROM_INT(GPIO_PULL_HOLD) },
328     { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(IRQ_TRIGGER_RISING_EDGE) },
329     { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(IRQ_TRIGGER_FALLING_EDGE) },
330     { MP_ROM_QSTR(MP_QSTR_WAKE_LOW), MP_ROM_INT(GPIO_PIN_INTR_LOLEVEL) },
331     { MP_ROM_QSTR(MP_QSTR_WAKE_HIGH), MP_ROM_INT(GPIO_PIN_INTR_HILEVEL) },
332 };
333 
pin_ioctl(mp_obj_t self_in,mp_uint_t request,uintptr_t arg,int * errcode)334 STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
335     (void)errcode;
336     machine_pin_obj_t *self = self_in;
337 
338     switch (request) {
339         case MP_PIN_READ: {
340             return mp_hal_pin_read(self->id);;
341         }
342         case MP_PIN_WRITE: {
343             return mp_hal_pin_write(self->id, arg);
344         }
345     }
346     return -1;
347 }
348 
349 STATIC MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table);
350 
351 STATIC const mp_pin_p_t pin_pin_p = {
352     .ioctl = pin_ioctl,
353 };
354 
355 const mp_obj_type_t machine_pin_type = {
356     { &mp_type_type },
357     .name = MP_QSTR_Pin,
358     .print = machine_pin_print,
359     .make_new = mp_pin_make_new,
360     .call = machine_pin_call,
361     .protocol = &pin_pin_p,
362     .locals_dict = (mp_obj_t)&machine_pin_locals_dict,
363 };
364 
365 #endif