kickstand
[aversive.git] / projects / microb2010 / ballboard / 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.2 2009-04-07 20:03:48 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 <blocking_detection_manager.h>
38
39 #include <rdline.h>
40 #include <parse.h>
41 #include <parse_string.h>
42 #include <parse_num.h>
43
44 #include "main.h"
45
46 /*
47  * Cmdline interface for AX12. Use the PC to command a daisy-chain of
48  * AX12 actuators with a nice command line interface.
49  * 
50  * The circuit should be as following:
51  *
52  *    |----------|
53  *    |     uart3|------->--- PC (baudrate=57600)
54  *    |          |-------<---
55  *    | atmega128|
56  *    |          |
57  *    |     uart0|---->---+-- AX12 (baudrate 115200)
58  *    |          |----<---| 
59  *    |----------|
60  *
61  * Note that RX and TX pins of UART1 are connected together to provide
62  * a half-duplex UART emulation.
63  *
64  */
65
66 #define UART_AX12_NUM 0
67 #define UCSRxB UCSR0B
68 #define AX12_TIMEOUT 5000UL /* in us */
69
70 /********************************* AX12 commands */
71
72 /*
73  * We use synchronous access (not interrupt driven) to the hardware
74  * UART, because we have to be sure that the transmission/reception is
75  * really finished when we return from the functions.
76  *
77  * We don't use the CM-5 circuit as described in the AX12
78  * documentation, we simply connect TX and RX and use TXEN + RXEN +
79  * DDR to manage the port directions.
80  */
81
82 static volatile uint8_t ax12_state = AX12_STATE_READ;
83 static volatile uint8_t ax12_nsent = 0;
84
85 /* Called by ax12 module to send a character on serial line. Count the
86  * number of transmitted bytes. It will be used in ax12_recv_char() to
87  * drop the bytes that we transmitted. */
88 static int8_t ax12_send_char(uint8_t c)
89 {
90         uart_send(UART_AX12_NUM, c);
91         ax12_nsent++;
92         return 0;
93 }
94
95 /* for atmega256 */
96 #ifndef TXEN
97 #define TXEN TXEN0
98 #endif
99
100 /* called by uart module when the character has been written in
101  * UDR. It does not mean that the byte is physically transmitted. */
102 static void ax12_send_callback(char c)
103 {
104         if (ax12_state == AX12_STATE_READ) {
105                 /* disable TX when last byte is pushed. */
106                 if (CIRBUF_IS_EMPTY(&g_tx_fifo[UART_AX12_NUM]))
107                         UCSRxB &= ~(1<<TXEN);
108         }
109 }
110
111 /* Called by ax12 module when we want to receive a char. Note that we
112  * also receive the bytes we sent ! So we need to drop them. */
113 static int16_t ax12_recv_char(void)
114 {
115         microseconds t = time_get_us2();
116         int c;
117         while (1) {
118                 c = uart_recv_nowait(UART_AX12_NUM);
119                 if (c != -1) {
120                         if (ax12_nsent == 0)
121                                 return c;
122                         ax12_nsent --;
123                 }
124
125                 /* 5 ms timeout */
126                 if ((time_get_us2() - t) > AX12_TIMEOUT)
127                         return -1;
128         }
129         return c;
130 }
131
132 /* called by ax12 module when we want to switch serial line. As we
133  * work in interruption mode, this function can be called to switch
134  * back in read mode even if the bytes are not really transmitted on
135  * the line. That's why in this case we do nothing, we will fall back
136  * in read mode in any case when xmit is finished -- see in
137  * ax12_send_callback() -- */
138 static void ax12_switch_uart(uint8_t state)
139 {
140         uint8_t flags;
141
142         if (state == AX12_STATE_WRITE) {
143                 IRQ_LOCK(flags);
144                 ax12_nsent=0;
145                 while (uart_recv_nowait(UART_AX12_NUM) != -1);
146                 UCSRxB |= (1<<TXEN);
147                 ax12_state = AX12_STATE_WRITE;
148                 IRQ_UNLOCK(flags);
149         }
150         else {
151                 IRQ_LOCK(flags);
152                 if (CIRBUF_IS_EMPTY(&g_tx_fifo[UART_AX12_NUM]))
153                         UCSRxB &= ~(1<<TXEN);
154                 ax12_state = AX12_STATE_READ;
155                 IRQ_UNLOCK(flags);
156         }
157 }
158
159
160 void ax12_user_init(void)
161 {
162         /* AX12 */
163         AX12_init(&gen.ax12);
164         AX12_set_hardware_send(&gen.ax12, ax12_send_char);
165         AX12_set_hardware_recv(&gen.ax12, ax12_recv_char);
166         AX12_set_hardware_switch(&gen.ax12, ax12_switch_uart);
167         uart_register_tx_event(UART_AX12_NUM, ax12_send_callback);
168 }