4 * Copyright 2006 Develer S.r.l. (http://www.develer.com/)
7 * \brief Implementation of the command protocol between the board and the host
12 * \author Giovanni Bajo <rasky@develer.com>
13 * \author Marco Benelli <marco@develer.com>
14 * \author Bernardo Innocenti <bernie@develer.com>
19 *#* Revision 1.1 2006/06/01 12:29:21 marco
20 *#* Add first simple protocol command (version request).
27 #include <mware/readline.h>
28 #include <mware/parser.h>
29 #include <cfg/compiler.h>
30 #include <cfg/debug.h>
36 // DEBUG: set to 1 to force interactive mode
37 #define FORCE_INTERACTIVE 1
40 * True if we are in interactive mode, false if we are in protocol mode.
41 * In interactive mode, commands are read through readline() (prompt, completion,
42 * history) without IDs, and replies/errors are sent to the serial output.
43 * In protocol mode, we implement the default protocol
45 static bool interactive;
47 /// Readline context, used for interactive mode.
48 static struct RLContext rl_ctx;
52 * Send a NAK asking the host to send the current message again.
54 * \param err human-readable description of the error for debug purposes.
56 INLINE void NAK(Serial *ser, const char *err)
59 ser_printf(ser, "NAK \"%s\"\r\n", err);
61 ser_printf(ser, "NAK\r\n");
65 static void protocol_parse(Serial *ser, const char *buf)
67 const struct CmdTemplate *templ;
68 parms args[8]; // FIXME FIXME!!
70 templ = parser_get_cmd_template(buf);
74 NAK(ser, "invalid command");
78 // Extract the arguments for the command
79 if (!parser_get_cmd_arguments(buf, templ, args))
81 NAK(ser, "invalid arguments");
88 void protocol_run(Serial *ser)
90 // \todo to be removed, we could probably access the serial FIFO directly
91 static char linebuf[80];
95 ser_gets(ser, linebuf, sizeof(linebuf));
97 // reset serial port error anyway
98 ser_setstatus(ser, 0);
100 // check message minimum length
103 if (linebuf[0] == 0x1B && linebuf[1] == 0x1B) // ESC
106 ser_printf(ser, "Entering interactive mode\r\n");
109 protocol_parse(ser, linebuf);
117 * Read a line from serial. We use a temporary buffer
118 * because otherwise we would have to extract a message
119 * from the port immediately: there might not be any
120 * available, and one might get free while we read
121 * the line. We also add a fake ID at the start to
124 buf = rl_readline(&rl_ctx);
126 if (buf && buf[0] != '\0')
128 // exit special case to immediately change serial input
129 if (!strcmp(buf, "exit") || !strcmp(buf, "quit"))
131 rl_clear_history(&rl_ctx);
132 ser_printf(ser, "Leaving interactive mode...\r\n");
133 interactive = FORCE_INTERACTIVE;
137 //TODO: remove sequence numbers
141 strncpy(linebuf + 2, buf, sizeof(linebuf) - 3);
142 linebuf[sizeof(linebuf) - 1] = '\0';
143 protocol_parse(ser, linebuf);
149 static ResultCode cmd_ver(const char **str)
152 kprintf("hello, version world!\nver=" VERS_TAG "\n");
155 static ResultCode cmd_add_hunk(parms args_results[])
157 return cmd_ver(&args_results[0].s);
159 const struct CmdTemplate cmd_ver_template =
161 "ver", "", "d", cmd_add_hunk
164 static void protocol_registerCmds(void)
166 // parser_register_cmd(&CMD_HUNK_TEMPLATE(quit));
167 // parser_register_cmd(&CMD_HUNK_TEMPLATE(exit));
168 // parser_register_cmd(&CMD_HUNK_TEMPLATE(wait));
169 // parser_register_cmd(&CMD_HUNK_TEMPLATE(delay));
170 // parser_register_cmd(&CMD_HUNK_TEMPLATE(SYN));
171 // parser_register_cmd(&CMD_HUNK_TEMPLATE(RST));
172 // parser_register_cmd(&CMD_HUNK_TEMPLATE(skip_end));
173 // parser_register_cmd(&CMD_HUNK_TEMPLATE(restart));
174 // parser_register_cmd(&CMD_HUNK_TEMPLATE(ver));
175 // parser_register_cmd(&CMD_HUNK_TEMPLATE(power_off));
177 parser_register_cmd(&cmd_ver_template);
179 void protocol_init(Serial *ser)
181 interactive = FORCE_INTERACTIVE;
183 // Initialize the readline context used for interactive mode
184 rl_init_ctx(&rl_ctx);
185 rl_setprompt(&rl_ctx, ">> ");
186 rl_sethook_get(&rl_ctx, (getc_hook)ser_getchar, ser);
187 rl_sethook_put(&rl_ctx, (putc_hook)ser_putchar, ser);
188 rl_sethook_match(&rl_ctx, parser_rl_match, NULL);
192 protocol_registerCmds();