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