config: add support of attiny45
[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 #ifndef HOST_VERSION
90
91 static volatile uint8_t ax12_state = AX12_STATE_READ;
92 static volatile uint8_t ax12_nsent = 0;
93
94 /* Called by ax12 module to send a character on serial line. Count the
95  * number of transmitted bytes. It will be used in ax12_recv_char() to
96  * drop the bytes that we transmitted. */
97 static int8_t ax12_send_char(uint8_t c)
98 {
99         uart_send(UART_AX12_NUM, c);
100         ax12_nsent++;
101         return 0;
102 }
103
104 /* for atmega256 */
105 #ifndef TXEN
106 #define TXEN TXEN0
107 #endif
108
109 /* called by uart module when the character has been written in
110  * UDR. It does not mean that the byte is physically transmitted. */
111 static void ax12_send_callback(char c)
112 {
113         if (ax12_state == AX12_STATE_READ) {
114                 /* disable TX when last byte is pushed. */
115                 if (CIRBUF_IS_EMPTY(&g_tx_fifo[UART_AX12_NUM]))
116                         UCSRxB &= ~(1<<TXEN);
117         }
118 }
119
120 /* Called by ax12 module when we want to receive a char. Note that we
121  * also receive the bytes we sent ! So we need to drop them. */
122 static int16_t ax12_recv_char(void)
123 {
124         microseconds t = time_get_us2();
125         int c;
126         while (1) {
127                 c = uart_recv_nowait(UART_AX12_NUM);
128                 if (c != -1) {
129                         if (ax12_nsent == 0)
130                                 return c;
131                         ax12_nsent --;
132                 }
133
134                 /* 5 ms timeout */
135                 if ((time_get_us2() - t) > AX12_TIMEOUT)
136                         return -1;
137         }
138         return c;
139 }
140
141 /* called by ax12 module when we want to switch serial line. As we
142  * work in interruption mode, this function can be called to switch
143  * back in read mode even if the bytes are not really transmitted on
144  * the line. That's why in this case we do nothing, we will fall back
145  * in read mode in any case when xmit is finished -- see in
146  * ax12_send_callback() -- */
147 static void ax12_switch_uart(uint8_t state)
148 {
149         uint8_t flags;
150
151         if (state == AX12_STATE_WRITE) {
152                 IRQ_LOCK(flags);
153                 ax12_nsent=0;
154                 while (uart_recv_nowait(UART_AX12_NUM) != -1);
155                 UCSRxB |= (1<<TXEN);
156                 ax12_state = AX12_STATE_WRITE;
157                 IRQ_UNLOCK(flags);
158         }
159         else {
160                 IRQ_LOCK(flags);
161                 if (CIRBUF_IS_EMPTY(&g_tx_fifo[UART_AX12_NUM]))
162                         UCSRxB &= ~(1<<TXEN);
163                 ax12_state = AX12_STATE_READ;
164                 IRQ_UNLOCK(flags);
165         }
166 }
167 #endif
168
169 void ax12_user_init(void)
170 {
171 #ifdef HOST_VERSION
172         return;
173 #else
174         /* AX12 */
175         AX12_init(&gen.ax12);
176         AX12_set_hardware_send(&gen.ax12, ax12_send_char);
177         AX12_set_hardware_recv(&gen.ax12, ax12_recv_char);
178         AX12_set_hardware_switch(&gen.ax12, ax12_switch_uart);
179         uart_register_tx_event(UART_AX12_NUM, ax12_send_callback);
180 #endif
181 }