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 "ulog/ulog.h"
35 
36 #include "py/builtin.h"
37 #include "py/mperrno.h"
38 #include "py/obj.h"
39 #include "py/runtime.h"
40 #include "py/gc.h"
41 #include "py/stackctrl.h"
42 
43 #include "utility.h"
44 #include "ulog/ulog.h"
45 #include "aos_hal_timer.h"
46 
47 #define LOG_TAG "machine_timer"
48 
49 #define TIMER_MODE_ONE_SHOT (TIMER_RELOAD_MANU)
50 #define TIMER_MODE_PERIODIC (TIMER_RELOAD_AUTO)
51 #define TIMER_DEFAULT_PERIOD (1000000U)
52 typedef struct _machine_timer_obj_t {
53     mp_obj_base_t base;
54     mp_uint_t port;
55     timer_dev_t *device;
56     mp_obj_t callback;
57 } machine_timer_obj_t;
58 
59 const mp_obj_type_t machine_timer_type;
60 
61 STATIC void machine_timer_disable(machine_timer_obj_t *self);
62 
machine_timer_get_devive(machine_timer_obj_t * self)63 STATIC timer_dev_t *machine_timer_get_devive(machine_timer_obj_t *self) {
64     if (self == NULL) {
65         LOGE(LOG_TAG, "machine_timer_obj is NULL\n");
66         return NULL;
67     }
68 
69     if(self->device != NULL) {
70         return self->device;
71     } else {
72         timer_dev_t *device = aos_calloc(1, sizeof(timer_dev_t));
73         if (NULL == device) {
74             LOGE(LOG_TAG, "%s: timer_dev_t calloc failed;\n", __func__);
75             goto fail;
76         }
77         device->port = self->port;
78         self->device = device;
79     }
80 
81     return self->device;
82 
83 fail:
84     self->device = NULL;
85     return NULL;
86 }
87 
machine_timer_print(const mp_print_t * print,mp_obj_t self_in,mp_print_kind_t kind)88 STATIC void machine_timer_print(const mp_print_t *print, mp_obj_t self_in,
89                                mp_print_kind_t kind) {
90     machine_timer_obj_t *self = MP_OBJ_TO_PTR(self_in);
91     mp_printf(print, "period=%d, ", self->device->config.period);
92     mp_printf(print, "reload_mode=%d, ", self->device->config.reload_mode);
93 }
94 
machine_timer_make_new(const mp_obj_type_t * type,size_t n_args,size_t n_kw,const mp_obj_t * args)95 STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args,
96                                        size_t n_kw, const mp_obj_t *args) {
97     mp_arg_check_num(n_args, n_kw, 1, 1, false);
98     mp_uint_t port = mp_obj_get_int(args[0]);
99 
100     machine_timer_obj_t *machine_obj = m_new_obj(machine_timer_obj_t);
101     if (!machine_obj) {
102         mp_raise_OSError(ENOMEM);
103         return mp_const_none;
104     }
105     machine_obj->base.type = &machine_timer_type;
106     machine_obj->port = port;
107     machine_obj->device = NULL;
108 
109     return MP_OBJ_FROM_PTR(machine_obj);
110 }
111 
machine_timer_disable(machine_timer_obj_t * self)112 STATIC void machine_timer_disable(machine_timer_obj_t *self) {
113     timer_dev_t *tim = machine_timer_get_devive(self);
114     aos_hal_timer_stop(tim);
115 }
116 
machine_timer_isr(void * self_in)117 STATIC void machine_timer_isr(void *self_in) {
118     machine_timer_obj_t *self = (machine_timer_obj_t*)self_in;
119     mp_obj_t callback = self->callback;
120     if (self->callback != mp_const_none) {
121         callback_to_python(self->callback, self);
122     }
123 }
124 
machine_timer_enable(machine_timer_obj_t * self)125 STATIC void machine_timer_enable(machine_timer_obj_t *self) {
126     timer_dev_t *tim = machine_timer_get_devive(self);
127     if(tim != NULL) {
128         aos_hal_timer_init(tim);
129         aos_hal_timer_start(tim);
130     }
131 }
132 
machine_timer_init_helper(machine_timer_obj_t * self,mp_uint_t n_args,const mp_obj_t * pos_args,mp_map_t * kw_args)133 STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self,
134                                           mp_uint_t n_args,
135                                           const mp_obj_t *pos_args,
136                                           mp_map_t *kw_args) {
137     enum
138     {
139         ARG_index,
140         ARG_mode,
141         ARG_callback,
142         ARG_period,
143     };
144     static const mp_arg_t allowed_args[] = {
145         {MP_QSTR_index, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0}},
146         {MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = TIMER_MODE_PERIODIC}},
147         {MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none}},
148         {MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = TIMER_DEFAULT_PERIOD}},
149     };
150 
151     machine_timer_disable(self);
152 
153     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
154     mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args),
155                      allowed_args, args);
156 
157     if (self == NULL || self->device == NULL) {
158         LOGE(LOG_TAG, "%s: hal_timer_init failed\n", __func__);
159         return mp_const_none;
160     }
161 
162     self->callback = args[ARG_callback].u_obj;
163     self->device->port = (int8_t)args[ARG_index].u_int;
164     self->device->config.reload_mode = args[ARG_mode].u_int;
165     self->device->config.period = (uint32_t)args[ARG_period].u_int * 1000UL;
166     self->device->config.arg = self;
167     self->device->config.cb = machine_timer_isr;
168 
169     machine_timer_enable(self);
170     return mp_const_none;
171 }
172 
machine_timer_deinit(mp_obj_t self_in)173 STATIC mp_obj_t machine_timer_deinit(mp_obj_t self_in) {
174     machine_timer_obj_t *self = MP_OBJ_TO_PTR(self_in);
175     machine_timer_disable(self);
176     timer_dev_t *tim = machine_timer_get_devive(self);
177     if(tim != NULL) {
178         aos_free(tim);
179         self->device = NULL;
180     }
181     aos_hal_timer_stop(tim);
182     return mp_const_none;
183 }
184 STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_deinit_obj, machine_timer_deinit);
185 
machine_timer_init(mp_uint_t n_args,const mp_obj_t * args,mp_map_t * kw_args)186 STATIC mp_obj_t machine_timer_init(mp_uint_t n_args, const mp_obj_t *args,
187                                    mp_map_t *kw_args) {
188     return machine_timer_init_helper(args[0], n_args - 1, args + 1, kw_args);
189 }
190 STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_timer_init_obj, 1, machine_timer_init);
191 
machine_timer_period(mp_obj_t self_in,mp_const_obj_t period)192 STATIC mp_obj_t machine_timer_period(mp_obj_t self_in, mp_const_obj_t period)
193 {
194     machine_timer_obj_t *self = self_in;
195     if(self_in == NULL) {
196         mp_raise_OSError(ENOENT);
197         return mp_const_none;
198     } else {
199         self->device->config.period = mp_obj_get_int(period);
200     }
201     timer_config_t para = self->device->config;
202 
203     timer_dev_t *tim = machine_timer_get_devive(self);
204     int32_t ret = aos_hal_timer_para_chg(tim, para);
205     return MP_OBJ_NEW_SMALL_INT(ret);
206 }
207 STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_timer_period_obj, machine_timer_period);
208 
machine_timer_start(mp_obj_t self_in)209 STATIC mp_obj_t machine_timer_start(mp_obj_t self_in) {
210     machine_timer_obj_t *self = self_in;
211     timer_dev_t *tim = machine_timer_get_devive(self);
212     int32_t ret = aos_hal_timer_start(tim);
213     return MP_OBJ_NEW_SMALL_INT(ret);
214 }
215 STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_start_obj, machine_timer_start);
216 
machine_timer_stop(mp_obj_t self_in)217 STATIC mp_obj_t machine_timer_stop(mp_obj_t self_in) {
218     machine_timer_obj_t *self = self_in;
219     timer_dev_t *tim = machine_timer_get_devive(self);
220     aos_hal_timer_stop(tim);
221     return mp_const_none;
222 }
223 STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_stop_obj, machine_timer_stop);
224 
machine_timer_value(mp_obj_t self_in)225 STATIC mp_obj_t machine_timer_value(mp_obj_t self_in) {
226     machine_timer_obj_t *self = self_in;
227     double result = 1.0;
228 
229     LOGI(LOG_TAG, "hardware timer doesn't support value get, default to 1s");
230 
231     return MP_OBJ_NEW_SMALL_INT((mp_uint_t)(result * 1000));  // value in ms
232 }
233 STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_value_obj, machine_timer_value);
234 
235 STATIC const mp_rom_map_elem_t machine_timer_locals_dict_table[] = {
236     {MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&machine_timer_deinit_obj)},
237     {MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_timer_init_obj)},
238     {MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_timer_deinit_obj)},
239     {MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&machine_timer_start_obj)},
240     {MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&machine_timer_stop_obj)},
241     {MP_ROM_QSTR(MP_QSTR_period), MP_ROM_PTR(&machine_timer_period_obj)},
242     {MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_timer_value_obj)},
243 
244     {MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(TIMER_MODE_ONE_SHOT)},
245     {MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(TIMER_MODE_PERIODIC)},
246 };
247 STATIC MP_DEFINE_CONST_DICT(machine_timer_locals_dict, machine_timer_locals_dict_table);
248 
249 const mp_obj_type_t machine_timer_type = {
250     {&mp_type_type},
251     .name = MP_QSTR_Timer,
252     .print = machine_timer_print,
253     .make_new = machine_timer_make_new,
254     .locals_dict = (mp_obj_t)&machine_timer_locals_dict,
255 };
256