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