beacon
[aversive.git] / projects / microb2010 / mainboard / ax12_user.c
1 /*  
2  *  Copyright Droids Corporation
3  *  Olivier Matz <zer0@droids-corp.org>
4  * 
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  *  Revision : $Id: ax12_user.c,v 1.3 2009-05-02 10:08:09 zer0 Exp $
20  *
21  */
22
23 #include <aversive.h>
24 #include <aversive/list.h>
25 #include <aversive/error.h>
26
27 #include <i2c.h>
28 #include <ax12.h>
29 #include <uart.h>
30 #include <pwm_ng.h>
31 #include <clock_time.h>
32 #include <spi.h>
33
34 #include <pid.h>
35 #include <quadramp.h>
36 #include <control_system_manager.h>
37 #include <trajectory_manager.h>
38 #include <vect_base.h>
39 #include <lines.h>
40 #include <polygon.h>
41 #include <obstacle_avoidance.h>
42 #include <blocking_detection_manager.h>
43 #include <robot_system.h>
44 #include <position_manager.h>
45
46 #include <rdline.h>
47 #include <parse.h>
48 #include <parse_string.h>
49 #include <parse_num.h>
50
51 #include "main.h"
52
53 /*
54  * Cmdline interface for AX12. Use the PC to command a daisy-chain of
55  * AX12 actuators with a nice command line interface.
56  * 
57  * The circuit should be as following:
58  *
59  *    |----------|
60  *    |     uart3|------->--- PC (baudrate=57600)
61  *    |          |-------<---
62  *    | atmega128|
63  *    |          |
64  *    |     uart0|---->---+-- AX12 (baudrate 115200)
65  *    |          |----<---| 
66  *    |----------|
67  *
68  * Note that RX and TX pins of UART1 are connected together to provide
69  * a half-duplex UART emulation.
70  *
71  */
72
73 #define UART_AX12_NUM 0
74 #define UCSRxB UCSR0B
75 #define AX12_TIMEOUT 5000UL /* in us */
76
77 /********************************* AX12 commands */
78
79 /*
80  * We use synchronous access (not interrupt driven) to the hardware
81  * UART, because we have to be sure that the transmission/reception is
82  * really finished when we return from the functions.
83  *
84  * We don't use the CM-5 circuit as described in the AX12
85  * documentation, we simply connect TX and RX and use TXEN + RXEN +
86  * DDR to manage the port directions.
87  */
88
89 static volatile uint8_t ax12_state = AX12_STATE_READ;
90 extern volatile struct cirbuf g_tx_fifo[]; /* uart fifo */
91 static volatile uint8_t ax12_nsent = 0;
92
93 /* Called by ax12 module to send a character on serial line. Count the
94  * number of transmitted bytes. It will be used in ax12_recv_char() to
95  * drop the bytes that we transmitted. */
96 static int8_t ax12_send_char(uint8_t c)
97 {
98         uart_send(UART_AX12_NUM, c);
99         ax12_nsent++;
100         return 0;
101 }
102
103 /* for atmega256 */
104 #ifndef TXEN
105 #define TXEN TXEN0
106 #endif
107
108 /* called by uart module when the character has been written in
109  * UDR. It does not mean that the byte is physically transmitted. */
110 static void ax12_send_callback(char c)
111 {
112         if (ax12_state == AX12_STATE_READ) {
113                 /* disable TX when last byte is pushed. */
114                 if (CIRBUF_IS_EMPTY(&g_tx_fifo[UART_AX12_NUM]))
115                         UCSRxB &= ~(1<<TXEN);
116         }
117 }
118
119 /* Called by ax12 module when we want to receive a char. Note that we
120  * also receive the bytes we sent ! So we need to drop them. */
121 static int16_t ax12_recv_char(void)
122 {
123         microseconds t = time_get_us2();
124         int c;
125         while (1) {
126                 c = uart_recv_nowait(UART_AX12_NUM);
127                 if (c != -1) {
128                         if (ax12_nsent == 0)
129                                 return c;
130                         ax12_nsent --;
131                 }
132
133                 /* 5 ms timeout */
134                 if ((time_get_us2() - t) > AX12_TIMEOUT)
135                         return -1;
136         }
137         return c;
138 }
139
140 /* called by ax12 module when we want to switch serial line. As we
141  * work in interruption mode, this function can be called to switch
142  * back in read mode even if the bytes are not really transmitted on
143  * the line. That's why in this case we do nothing, we will fall back
144  * in read mode in any case when xmit is finished -- see in
145  * ax12_send_callback() -- */
146 static void ax12_switch_uart(uint8_t state)
147 {
148         uint8_t flags;
149
150         if (state == AX12_STATE_WRITE) {
151                 IRQ_LOCK(flags);
152                 ax12_nsent=0;
153                 while (uart_recv_nowait(UART_AX12_NUM) != -1);
154                 UCSRxB |= (1<<TXEN);
155                 ax12_state = AX12_STATE_WRITE;
156                 IRQ_UNLOCK(flags);
157         }
158         else {
159                 IRQ_LOCK(flags);
160                 if (CIRBUF_IS_EMPTY(&g_tx_fifo[UART_AX12_NUM]))
161                         UCSRxB &= ~(1<<TXEN);
162                 ax12_state = AX12_STATE_READ;
163                 IRQ_UNLOCK(flags);
164         }
165 }
166
167
168 void ax12_user_init(void)
169 {
170         /* AX12 */
171         AX12_init(&gen.ax12);
172         AX12_set_hardware_send(&gen.ax12, ax12_send_char);
173         AX12_set_hardware_recv(&gen.ax12, ax12_recv_char);
174         AX12_set_hardware_switch(&gen.ax12, ax12_switch_uart);
175         uart_register_tx_event(UART_AX12_NUM, ax12_send_callback);
176 }