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) 2013-2015 Damien P. George
9  * Copyright (c) 2016 Paul Sokolovsky
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27  * THE SOFTWARE.
28  */
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <vfsdev/timer_dev.h>
34 
35 #include "aos_hal_timer.h"
36 #include "py/builtin.h"
37 #include "py/gc.h"
38 #include "py/mperrno.h"
39 #include "py/obj.h"
40 #include "py/runtime.h"
41 #include "py/stackctrl.h"
42 #include "ulog/ulog.h"
43 #include "utility.h"
44 
45 #define LOG_TAG              "driver_timer"
46 
47 #define TIMER_MODE_ONESHOT   (TIMER_RELOAD_MANU)
48 #define TIMER_MODE_PERIODIC  (TIMER_RELOAD_AUTO)
49 #define TIMER_DEFAULT_PERIOD (1000000U)
50 typedef struct _driver_timer_obj_t {
51     mp_obj_base_t base;
52     mp_uint_t port;
53     timer_dev_t dev;
54     mp_obj_t callback;
55 } driver_timer_obj_t;
56 
57 const mp_obj_type_t driver_timer_type;
58 
driver_timer_print(const mp_print_t * print,mp_obj_t self_in,mp_print_kind_t kind)59 STATIC void driver_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind)
60 {
61     driver_timer_obj_t *self = MP_OBJ_TO_PTR(self_in);
62     mp_printf(print, "port=%d, ", self->port);
63     mp_printf(print, "period=%d, ", self->dev.config.period);
64     mp_printf(print, "reload_mode=%d, ", self->dev.config.reload_mode);
65 }
66 
driver_timer_make_new(const mp_obj_type_t * type,size_t n_args,size_t n_kw,const mp_obj_t * args)67 STATIC mp_obj_t driver_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args)
68 {
69     mp_arg_check_num(n_args, n_kw, 1, 1, false);
70     mp_uint_t port = mp_obj_get_int(args[0]);
71 
72     driver_timer_obj_t *timer_obj = m_new_obj(driver_timer_obj_t);
73     if (!timer_obj) {
74         mp_raise_OSError(MP_EINVAL);
75         return mp_const_none;
76     }
77     memset(timer_obj, 0, sizeof(driver_timer_obj_t));
78 
79     timer_obj->base.type = &driver_timer_type;
80     timer_obj->port = port;
81     timer_obj->dev.port = port;
82 
83     return MP_OBJ_FROM_PTR(timer_obj);
84 }
85 
driver_timer_disable(timer_dev_t * tim)86 STATIC void driver_timer_disable(timer_dev_t *tim)
87 {
88     aos_hal_timer_stop(tim);
89 }
90 
aos_hal_timer_reload(timer_dev_t * tim)91 STATIC mp_int_t aos_hal_timer_reload(timer_dev_t *tim)
92 {
93     int32_t *p_fd = (int32_t *)tim->priv;
94     return ioctl(*p_fd, IOC_TIMER_RELOAD, (unsigned long)false);
95 }
96 
driver_timer_isr(void * self_in)97 STATIC void driver_timer_isr(void *self_in)
98 {
99     driver_timer_obj_t *self = (driver_timer_obj_t *)self_in;
100     mp_obj_t callback = self->callback;
101     if (callback != mp_const_none && mp_obj_is_callable(callback)) {
102         callback_to_python(callback, self);
103     }
104 }
105 
driver_timer_enable(driver_timer_obj_t * self)106 STATIC mp_int_t driver_timer_enable(driver_timer_obj_t *self)
107 {
108     mp_int_t ret = -1;
109     timer_dev_t *tim = &self->dev;
110     if (tim != NULL) {
111         ret = aos_hal_timer_init(tim);
112         ret = aos_hal_timer_start(tim);
113     }
114 
115     return ret;
116 }
117 
driver_timer_init_helper(driver_timer_obj_t * self,mp_uint_t n_args,const mp_obj_t * pos_args,mp_map_t * kw_args)118 STATIC mp_obj_t driver_timer_init_helper(driver_timer_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args,
119                                          mp_map_t *kw_args)
120 {
121     enum {
122         ARG_period,
123         ARG_mode,
124         ARG_callback,
125     };
126     static const mp_arg_t allowed_args[] = {
127         { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = TIMER_DEFAULT_PERIOD } },
128         { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = TIMER_MODE_PERIODIC } },
129         { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = mp_const_none } },
130     };
131 
132     driver_timer_disable(&self->dev);
133 
134     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
135     mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
136 
137     if (self == NULL) {
138         LOGE(LOG_TAG, "%s: hal_timer_init failed\n", __func__);
139         return mp_const_none;
140     }
141 
142     self->callback = args[ARG_callback].u_obj;
143     self->dev.port = self->port;
144     self->dev.config.reload_mode = args[ARG_mode].u_int;
145     self->dev.config.period = (mp_uint_t)args[ARG_period].u_int * 1000UL;
146     self->dev.config.arg = self;
147     self->dev.config.cb = driver_timer_isr;
148 
149     mp_int_t ret = driver_timer_enable(self);
150     return MP_OBJ_NEW_SMALL_INT(ret);
151 }
152 
driver_timer_close(mp_obj_t self_in)153 STATIC mp_obj_t driver_timer_close(mp_obj_t self_in)
154 {
155     driver_timer_obj_t *self = MP_OBJ_TO_PTR(self_in);
156     timer_dev_t *tim = &self->dev;
157     aos_hal_timer_stop(tim);
158     mp_int_t ret = aos_hal_timer_finalize(tim);
159     return MP_OBJ_NEW_SMALL_INT(ret);
160 }
161 STATIC MP_DEFINE_CONST_FUN_OBJ_1(driver_timer_close_obj, driver_timer_close);
162 
driver_timer_open(size_t n_args,const mp_obj_t * args,mp_map_t * kw_args)163 STATIC mp_obj_t driver_timer_open(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args)
164 {
165     return driver_timer_init_helper(args[0], n_args - 1, args + 1, kw_args);
166 }
167 STATIC MP_DEFINE_CONST_FUN_OBJ_KW(driver_timer_open_obj, 1, driver_timer_open);
168 
driver_timer_period(mp_obj_t self_in,mp_obj_t period)169 STATIC mp_obj_t driver_timer_period(mp_obj_t self_in, mp_obj_t period)
170 {
171     driver_timer_obj_t *self = self_in;
172     if (self_in == NULL) {
173         mp_raise_OSError(MP_EINVAL);
174         return mp_const_none;
175     } else {
176         self->dev.config.period = mp_obj_get_int(period);
177     }
178     timer_config_t para = self->dev.config;
179 
180     timer_dev_t *tim = &self->dev;
181     mp_int_t ret = aos_hal_timer_para_chg(tim, para);
182     return MP_OBJ_NEW_SMALL_INT(ret);
183 }
184 STATIC MP_DEFINE_CONST_FUN_OBJ_2(driver_timer_period_obj, driver_timer_period);
185 
driver_timer_start(mp_obj_t self_in)186 STATIC mp_obj_t driver_timer_start(mp_obj_t self_in)
187 {
188     driver_timer_obj_t *self = self_in;
189     timer_dev_t *tim = &self->dev;
190     mp_int_t ret = aos_hal_timer_start(tim);
191     return MP_OBJ_NEW_SMALL_INT(ret);
192 }
193 STATIC MP_DEFINE_CONST_FUN_OBJ_1(driver_timer_start_obj, driver_timer_start);
194 
driver_timer_stop(mp_obj_t self_in)195 STATIC mp_obj_t driver_timer_stop(mp_obj_t self_in)
196 {
197     driver_timer_obj_t *self = self_in;
198     timer_dev_t *tim = &self->dev;
199     aos_hal_timer_stop(tim);
200     return MP_OBJ_NEW_SMALL_INT(0);
201 }
202 STATIC MP_DEFINE_CONST_FUN_OBJ_1(driver_timer_stop_obj, driver_timer_stop);
203 
driver_timer_reload(mp_obj_t self_in)204 STATIC mp_obj_t driver_timer_reload(mp_obj_t self_in)
205 {
206     driver_timer_obj_t *self = self_in;
207     timer_dev_t *tim = &self->dev;
208     mp_int_t ret = aos_hal_timer_reload(tim);
209     return MP_OBJ_NEW_SMALL_INT(ret);
210 }
211 STATIC MP_DEFINE_CONST_FUN_OBJ_1(driver_timer_reload_obj, driver_timer_reload);
212 STATIC const mp_rom_map_elem_t driver_timer_locals_dict_table[] = {
213     { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&driver_timer_open_obj) },
214     { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&driver_timer_close_obj) },
215     { MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&driver_timer_start_obj) },
216     { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&driver_timer_stop_obj) },
217     { MP_ROM_QSTR(MP_QSTR_period), MP_ROM_PTR(&driver_timer_period_obj) },
218     { MP_ROM_QSTR(MP_QSTR_reload), MP_ROM_PTR(&driver_timer_reload_obj) },
219 
220     { MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(TIMER_MODE_ONESHOT) },
221     { MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(TIMER_MODE_PERIODIC) },
222 };
223 STATIC MP_DEFINE_CONST_DICT(driver_timer_locals_dict, driver_timer_locals_dict_table);
224 
225 const mp_obj_type_t driver_timer_type = {
226     { &mp_type_type },
227     .name = MP_QSTR_TIMER,
228     .print = driver_timer_print,
229     .make_new = driver_timer_make_new,
230     .locals_dict = (mp_obj_t)&driver_timer_locals_dict,
231 };
232