2 * Copyright Droids Corporation
3 * Olivier Matz <zer0@droids-corp.org>
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.
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.
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
19 * Revision : $Id: main.c,v 1.1.4.4 2008-12-27 16:29:08 zer0 Exp $
24 * Cmdline interface for AX12. Use the PC to command a daisy-chain of
25 * AX12 actuators with a nice command line interface.
27 * The circuit should be as following:
30 * | uart0|------->--- PC (baudrate=57600)
34 * | uart1|---->---+-- AX12 (baudrate 1 000 000)
38 * Note that RX and TX pins of UART1 are connected together to provide
39 * a half-duplex UART emulation.
47 #include <aversive/pgmspace.h>
48 #include <aversive/wait.h>
54 #include <scheduler.h>
58 /* for cmdline interface */
60 char prompt[RDLINE_PROMPT_SIZE];
61 extern parse_pgm_ctx_t main_ctx[];
63 /* structure defining the AX12 servo */
66 /******** For cmdline. See in commands.c for the list of commands. */
67 static void write_char(char c)
73 valid_buffer(const char * buf, uint8_t size)
76 ret = parse(main_ctx, buf);
77 if (ret == PARSE_AMBIGUOUS)
78 printf_P(PSTR("Ambiguous command\r\n"));
79 else if (ret == PARSE_NOMATCH)
80 printf_P(PSTR("Command not found\r\n"));
81 else if (ret == PARSE_BAD_ARGS)
82 printf_P(PSTR("Bad arguments\r\n"));
86 complete_buffer(const char * buf, char * dstbuf, uint8_t dstsize,
89 return complete(main_ctx, buf, state, dstbuf, dstsize);
92 /********************************* AX12 commands */
97 * We use synchronous access (not interrupt driven) to the hardware
98 * UART, because we have to be sure that the transmission/reception is
99 * really finished when we return from the functions.
101 * We don't use the CM-5 circuit as described in the AX12
102 * documentation, we simply connect TX and RX and use TXEN + RXEN +
103 * DDR to manage the port directions.
106 static volatile uint8_t ax12_state = AX12_STATE_READ;
107 extern volatile struct cirbuf g_tx_fifo[]; /* uart fifo */
108 static volatile uint8_t ax12_nsent = 0;
110 /* Called by ax12 module to send a character on serial line. Count the
111 * number of transmitted bytes. It will be used in ax12_recv_char() to
112 * drop the bytes that we transmitted. */
113 static int8_t ax12_send_char(uint8_t c)
120 /* called by uart module when the character has been written in
121 * UDR. It does not mean that the byte is physically transmitted. */
122 static void ax12_send_callback(char c)
124 if (ax12_state == AX12_STATE_READ) {
125 /* disable TX when last byte is pushed. */
126 if (CIRBUF_IS_EMPTY(&g_tx_fifo[1]))
127 UCSR1B &= ~(1<<TXEN);
131 /* Called by ax12 module when we want to receive a char. Note that we
132 * also receive the bytes we sent ! So we need to drop them. */
133 static int16_t ax12_recv_char(void)
135 microseconds t = time_get_us2();
138 c = uart_recv_nowait(1);
146 if ((time_get_us2() - t) > 50000)
152 /* called by ax12 module when we want to switch serial line. As we
153 * work in interruption mode, this function can be called to switch
154 * back in read mode even if the bytes are not really transmitted on
155 * the line. That's why in this case we do nothing, we will fall back
156 * in read mode in any case when xmit is finished -- see in
157 * ax12_send_callback() -- */
158 static void ax12_switch_uart(uint8_t state)
162 if (state == AX12_STATE_WRITE) {
166 ax12_state = AX12_STATE_WRITE;
171 if (CIRBUF_IS_EMPTY(&g_tx_fifo[1]))
172 UCSR1B &= ~(1<<TXEN);
173 ax12_state = AX12_STATE_READ;
178 static void main_timer_interrupt(void)
180 static uint8_t cpt = 0;
184 if ((cpt & 0x3) == 0)
185 scheduler_interrupt();
188 /***********************/
193 const char * history;
200 ax12_switch_uart(AX12_STATE_READ);
201 fdevopen(uart0_dev_send, uart0_dev_recv);
205 AX12_set_hardware_send(&ax12, ax12_send_char);
206 AX12_set_hardware_recv(&ax12, ax12_recv_char);
207 AX12_set_hardware_switch(&ax12, ax12_switch_uart);
208 uart_register_tx_event(1, ax12_send_callback);
212 timer0_register_OV_intr(main_timer_interrupt);
219 /* set status return level to 2 and torque to 0 */
220 AX12_write_int(&ax12,0xFE, AA_TORQUE_ENABLE, 0x00);
221 AX12_write_byte(&ax12, 0xFE, AA_STATUS_RETURN_LEVEL, 2);
223 rdline_init(&rdl, write_char, valid_buffer, complete_buffer);
224 snprintf(prompt, sizeof(prompt), "ax12 > ");
225 rdline_newline(&rdl, prompt);
227 /* waiting for commands now... */
230 c = uart_recv_nowait(0);
233 ret = rdline_char_in(&rdl, c);
234 if (ret != 2 && ret != 0) {
235 history = rdline_get_buffer(&rdl);
236 if (strlen(history) > 1)
237 rdline_add_history(&rdl, history);
238 rdline_newline(&rdl, prompt);