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 
34 #include "k_api.h"
35 #include "py/builtin.h"
36 #include "py/mperrno.h"
37 #include "py/obj.h"
38 #include "py/runtime.h"
39 #include "py/gc.h"
40 #include "py/stackctrl.h"
41 
42 #include "ulog/ulog.h"
43 #include "aos/kernel.h"
44 
45 #define LOG_TAG "machine_sw_timer"
46 
47 #define TIMER_MODE_ONE_SHOT (0)
48 #define TIMER_MODE_PERIODIC (AOS_TIMER_REPEAT)
49 #define TIMER_DEFAULT_PERIOD (1000000U)
50 
51 typedef struct _machine_soft_timer_obj_t {
52     mp_obj_base_t base;
53     mp_uint_t port;
54     mp_uint_t period;
55     mp_uint_t reload_mode;
56     void* arg;
57     aos_timer_t timerId;
58     mp_obj_t callback;
59 } machine_soft_timer_obj_t;
60 
61 const mp_obj_type_t mp_machine_soft_timer_type;
62 
machine_soft_timer_print(const mp_print_t * print,mp_obj_t self_in,mp_print_kind_t kind)63 STATIC void machine_soft_timer_print(const mp_print_t *print, mp_obj_t self_in,
64                                mp_print_kind_t kind) {
65     machine_soft_timer_obj_t *self = MP_OBJ_TO_PTR(self_in);
66     mp_printf(print, "period=%d, ", self->period);
67     mp_printf(print, "reload_mode=%d, ", self->reload_mode);
68 }
69 
machine_soft_timer_make_new(const mp_obj_type_t * type,size_t n_args,size_t n_kw,const mp_obj_t * args)70 STATIC mp_obj_t machine_soft_timer_make_new(const mp_obj_type_t *type, size_t n_args,
71                                        size_t n_kw, const mp_obj_t *args) {
72     mp_arg_check_num(n_args, n_kw, 1, 1, false);
73     mp_uint_t port = mp_obj_get_int(args[0]);
74 
75     machine_soft_timer_obj_t *swtimer_obj = m_new_obj(machine_soft_timer_obj_t);
76     if (!swtimer_obj) {
77         mp_raise_OSError(ENOMEM);
78         return mp_const_none;
79     }
80     swtimer_obj->base.type = &mp_machine_soft_timer_type;
81     swtimer_obj->port = port;
82     swtimer_obj->timerId = NULL;
83     swtimer_obj->callback = NULL;
84 
85     return MP_OBJ_FROM_PTR(swtimer_obj);
86 }
87 
machine_soft_timer_enable(machine_soft_timer_obj_t * self)88 STATIC void machine_soft_timer_enable(machine_soft_timer_obj_t *self) {
89     aos_timer_t tim = self->timerId;
90     aos_timer_start(&tim);
91 }
92 
machine_soft_timer_disable(machine_soft_timer_obj_t * self)93 STATIC void machine_soft_timer_disable(machine_soft_timer_obj_t *self) {
94     aos_timer_t tim = self->timerId;
95     aos_timer_stop(&tim);
96 }
97 
machine_soft_timer_isr(void * timer,void * self_in)98 STATIC void machine_soft_timer_isr(void *timer, void *self_in) {
99     machine_soft_timer_obj_t *self = (machine_soft_timer_obj_t *)MP_OBJ_TO_PTR(self_in);
100     mp_obj_t callback = self->callback;
101     if (self->callback != mp_const_none) {
102         callback_to_python(self->callback, self);
103     }
104 }
105 
machine_soft_timer_init_helper(machine_soft_timer_obj_t * self,mp_uint_t n_args,const mp_obj_t * pos_args,mp_map_t * kw_args)106 STATIC mp_obj_t machine_soft_timer_init_helper(machine_soft_timer_obj_t *self,
107                                           mp_uint_t n_args,
108                                           const mp_obj_t *pos_args,
109                                           mp_map_t *kw_args) {
110     enum
111     {
112         ARG_index,
113         ARG_mode,
114         ARG_callback,
115         ARG_period,
116     };
117     static const mp_arg_t allowed_args[] = {
118         {MP_QSTR_index, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0}},
119         {MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = AOS_TIMER_REPEAT | AOS_TIMER_AUTORUN}},
120         {MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none}},
121         {MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = TIMER_DEFAULT_PERIOD}},
122     };
123 
124     machine_soft_timer_disable(self);
125 
126     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
127     mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args),
128                      allowed_args, args);
129 
130     if (self == NULL) {
131         LOGD(LOG_TAG, "%s: machine_soft_timer_init_helper failed \n", __func__);
132         return mp_const_none;
133     }
134 
135     self->callback = args[ARG_callback].u_obj;
136     self->port = (int8_t)args[ARG_index].u_int;
137     self->reload_mode = args[ARG_mode].u_int;
138     self->period = (uint32_t)args[ARG_period].u_int;
139     self->arg = (void*)self;
140 
141     int32_t status = aos_timer_create(&self->timerId,
142                                         machine_soft_timer_isr,
143                                         self->arg,
144                                         self->period,
145                                         (self->reload_mode | AOS_TIMER_AUTORUN));
146     if (status != 0) {
147         LOGE(LOG_TAG, "%s, %d, aos_timer_create failed\n", __func__, __LINE__);
148         return mp_const_none;
149     }
150 
151     return mp_const_none;
152 }
153 
machine_soft_timer_deinit(mp_obj_t self_in)154 STATIC mp_obj_t machine_soft_timer_deinit(mp_obj_t self_in) {
155     machine_soft_timer_obj_t *self = (machine_soft_timer_obj_t *)MP_OBJ_TO_PTR(self_in);
156     machine_soft_timer_disable(self);
157     aos_timer_free(&self->timerId);
158     return mp_const_none;
159 }
160 STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_soft_timer_deinit_obj, machine_soft_timer_deinit);
161 
machine_soft_timer_init(size_t n_args,const mp_obj_t * args,mp_map_t * kw_args)162 STATIC mp_obj_t machine_soft_timer_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
163     return machine_soft_timer_init_helper(args[0], n_args - 1, args + 1, kw_args);
164 }
165 STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_soft_timer_init_obj, 1, machine_soft_timer_init);
166 
machine_soft_timer_period(mp_obj_t self_in,mp_obj_t period)167 STATIC mp_obj_t machine_soft_timer_period(mp_obj_t self_in, mp_obj_t period) {
168     machine_soft_timer_obj_t *self = (machine_soft_timer_obj_t *)MP_OBJ_TO_PTR(self_in);
169     if(self_in == NULL) {
170         mp_raise_OSError(ENOENT);
171         return mp_const_none;
172     } else {
173         self->period = mp_obj_get_int(period);
174     }
175 
176     int32_t ret = aos_timer_change(&self->timerId, self->period);
177     return MP_OBJ_NEW_SMALL_INT(ret);
178 }
179 STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_soft_timer_period_obj, machine_soft_timer_period);
180 
machine_soft_timer_start(mp_obj_t self_in)181 STATIC mp_obj_t machine_soft_timer_start(mp_obj_t self_in) {
182     machine_soft_timer_obj_t *self = (machine_soft_timer_obj_t *)MP_OBJ_TO_PTR(self_in);
183     int32_t ret = aos_timer_start(&self->timerId);
184     return MP_OBJ_NEW_SMALL_INT(ret);
185 }
186 STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_soft_timer_start_obj, machine_soft_timer_start);
187 
machine_soft_timer_stop(mp_obj_t self_in)188 STATIC mp_obj_t machine_soft_timer_stop(mp_obj_t self_in) {
189     machine_soft_timer_obj_t *self = (machine_soft_timer_obj_t *)MP_OBJ_TO_PTR(self_in);
190     aos_timer_stop(&self->timerId);
191     return mp_const_none;
192 }
193 STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_soft_timer_stop_obj, machine_soft_timer_stop);
194 
machine_soft_timer_value(mp_obj_t self_in)195 STATIC mp_obj_t machine_soft_timer_value(mp_obj_t self_in) {
196     machine_soft_timer_obj_t *self = (machine_soft_timer_obj_t *)MP_OBJ_TO_PTR(self_in);
197 
198     uint64_t time_ns[4] = {0};
199     aos_timer_gettime(&self->timerId, time_ns);
200 
201     return MP_OBJ_NEW_SMALL_INT((mp_uint_t)(time_ns[0] * 1000 + time_ns[1] / 10000000));  // value in ms
202 }
203 STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_soft_timer_value_obj, machine_soft_timer_value);
204 
205 STATIC const mp_rom_map_elem_t machine_soft_timer_locals_dict_table[] = {
206     {MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&machine_soft_timer_deinit_obj)},
207     {MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_soft_timer_init_obj)},
208     {MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_soft_timer_deinit_obj)},
209     {MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&machine_soft_timer_start_obj)},
210     {MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&machine_soft_timer_stop_obj)},
211     {MP_ROM_QSTR(MP_QSTR_period), MP_ROM_PTR(&machine_soft_timer_period_obj)},
212     {MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_soft_timer_value_obj)},
213 
214     {MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(TIMER_MODE_ONE_SHOT)},
215     {MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(TIMER_MODE_PERIODIC)},
216 };
217 STATIC MP_DEFINE_CONST_DICT(machine_soft_timer_locals_dict, machine_soft_timer_locals_dict_table);
218 
219 const mp_obj_type_t mp_machine_soft_timer_type = {
220     {&mp_type_type},
221     .name = MP_QSTR_SoftTimer,
222     .print = machine_soft_timer_print,
223     .make_new = machine_soft_timer_make_new,
224     .locals_dict = (mp_obj_t)&machine_soft_timer_locals_dict,
225 };
226