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