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