altos/test: Adjust CRC error rate after FEC fix
[fw/altos] / src / drivers / ao_servo.c
1 /*
2  * Copyright © 2016 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include "ao.h"
20 #include "ao_servo.h"
21 #include "ao_pwm.h"
22 #include "ao_exti.h"
23
24 static uint8_t  limit_wakeup;
25
26 static void
27 ao_limit_isr(void)
28 {
29         ao_wakeup(&limit_wakeup);
30 }
31
32 static void
33 ao_limit_enable(uint8_t dir)
34 {
35         if (dir == AO_SERVO_FORE)
36                 ao_exti_enable(AO_SERVO_LIMIT_FORE_PORT, AO_SERVO_LIMIT_FORE_BIT);
37         else
38                 ao_exti_enable(AO_SERVO_LIMIT_BACK_PORT, AO_SERVO_LIMIT_BACK_BIT);
39 }
40
41 static void
42 ao_limit_disable(uint8_t dir)
43 {
44         if (dir == AO_SERVO_FORE)
45                 ao_exti_disable(AO_SERVO_LIMIT_FORE_PORT, AO_SERVO_LIMIT_FORE_BIT);
46         else
47                 ao_exti_disable(AO_SERVO_LIMIT_BACK_PORT, AO_SERVO_LIMIT_BACK_BIT);
48 }
49
50 static uint8_t
51 ao_limit_get(uint8_t dir)
52 {
53         if (dir == AO_SERVO_FORE)
54                 return !ao_gpio_get(AO_SERVO_LIMIT_FORE_PORT, AO_SERVO_LIMIT_FORE_BIT, PIN);
55         else
56                 return !ao_gpio_get(AO_SERVO_LIMIT_BACK_PORT, AO_SERVO_LIMIT_BACK_BIT, PIN);
57 }
58
59 void
60 ao_servo_run(uint16_t speed, uint8_t dir, uint16_t timeout)
61 {
62         printf ("speed %d dir %d\n", speed, dir);
63
64         /* Turn on the motor */
65         ao_gpio_set(AO_SERVO_DIR_PORT, AO_SERVO_DIR_BIT, AO_SERVO_DIR_PIN, dir);
66         ao_pwm_set(AO_SERVO_SPEED_PWM, speed);
67
68         /* Wait until the limit sensor is triggered */
69         ao_arch_block_interrupts();
70         ao_limit_enable(dir);
71         while (!ao_limit_get(dir))
72                 if (ao_sleep_for(&limit_wakeup, timeout))
73                         break;
74         ao_limit_disable(dir);
75         ao_arch_release_interrupts();
76
77         /* Turn off the motor */
78         ao_pwm_set(AO_SERVO_SPEED_PWM, 0);
79 }
80
81 #define init_limit(p,b) do {                                            \
82                 ao_enable_port(p);                                      \
83                 ao_exti_setup(p, b,                                     \
84                               AO_EXTI_MODE_PULL_UP|AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED, \
85                               ao_limit_isr);                            \
86         } while (0)
87
88
89 static void
90 ao_servo_cmd(void)
91 {
92         uint8_t dir;
93         uint16_t speed;
94
95         ao_cmd_decimal();
96         dir = ao_cmd_lex_u32;
97         ao_cmd_decimal();
98         speed = ao_cmd_lex_u32;
99         if (ao_cmd_status != ao_cmd_success)
100                 return;
101
102         printf("Run servo %d\n", dir);
103         ao_servo_run(speed, dir, AO_MS_TO_TICKS(200));
104 }
105
106 static const struct ao_cmds ao_servo_cmds[] = {
107         { ao_servo_cmd, "S <dir> <speed>\0Run servo in indicated direction" },
108         { 0, NULL },
109 };
110
111
112 void
113 ao_servo_init(void)
114 {
115         init_limit(AO_SERVO_LIMIT_FORE_PORT, AO_SERVO_LIMIT_FORE_BIT);
116         init_limit(AO_SERVO_LIMIT_BACK_PORT, AO_SERVO_LIMIT_BACK_BIT);
117         ao_enable_output(AO_SERVO_DIR_PORT, AO_SERVO_DIR_BIT, AO_SERVO_DIR_PIN, 0);
118         ao_cmd_register(&ao_servo_cmds[0]);
119 }