1
|
|
2
|
/* (C) 2012 by Harald Welte <laforge@gnumonks.org>
|
3
|
*
|
4
|
* All Rights Reserved
|
5
|
*
|
6
|
* This program is free software; you can redistribute it and/or modify
|
7
|
* it under the terms of the GNU General Public License as published by
|
8
|
* the Free Software Foundation; either version 3 of the License, or
|
9
|
* (at your option) any later version.
|
10
|
*
|
11
|
* This program is distributed in the hope that it will be useful,
|
12
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
* GNU General Public License for more details.
|
15
|
*
|
16
|
* You should have received a copy of the GNU General Public License
|
17
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
|
*/
|
19
|
|
20
|
#include <string.h>
|
21
|
#include <stdint.h>
|
22
|
#include <stdio.h>
|
23
|
#include <errno.h>
|
24
|
#include <stdarg.h>
|
25
|
|
26
|
#include <uart_cmd.h>
|
27
|
|
28
|
void strbuf_reset(struct strbuf *sb)
|
29
|
{
|
30
|
sb->idx = 0;
|
31
|
memset(sb->buf, 0, sizeof(sb->buf));
|
32
|
}
|
33
|
|
34
|
void strbuf_append(struct strbuf *sb, char ch)
|
35
|
{
|
36
|
if (sb->idx < sizeof(sb->buf)-1)
|
37
|
sb->buf[sb->idx++] = ch;
|
38
|
}
|
39
|
|
40
|
static LLIST_HEAD(cmd_list);
|
41
|
|
42
|
void uart_cmd_register(struct cmd *c)
|
43
|
{
|
44
|
llist_add_tail(&c->list, &cmd_list);
|
45
|
}
|
46
|
|
47
|
void uart_cmd_unregister(struct cmd *c)
|
48
|
{
|
49
|
llist_del(&c->list);
|
50
|
}
|
51
|
|
52
|
void uart_cmds_register(struct cmd *c, unsigned int num)
|
53
|
{
|
54
|
int i;
|
55
|
|
56
|
for (i = 0; i < num; i++)
|
57
|
uart_cmd_register(&c[i]);
|
58
|
}
|
59
|
|
60
|
#define CMD_MAX_ARGS 10
|
61
|
|
62
|
static int handle_cb(struct cmd_state *cs, int op, char *cmd, char *arg)
|
63
|
{
|
64
|
struct cmd *c;
|
65
|
int rc;
|
66
|
char *argv[CMD_MAX_ARGS];
|
67
|
int argc = 0;
|
68
|
|
69
|
if (arg) {
|
70
|
char *tok;
|
71
|
/* tokenize the argument portion into individual arguments */
|
72
|
for (tok = strtok(arg, ","); tok; tok = strtok(NULL, ",")) {
|
73
|
if (argc >= CMD_MAX_ARGS)
|
74
|
break;
|
75
|
argv[argc++] = tok;
|
76
|
}
|
77
|
}
|
78
|
|
79
|
llist_for_each_entry(c, &cmd_list, list) {
|
80
|
if (!strcmp(c->cmd, cmd)) {
|
81
|
if (!(c->ops & op)) {
|
82
|
uart_cmd_out(cs, "Command `%s' doesn't "
|
83
|
"support this operation\n\r", c->cmd);
|
84
|
return -EINVAL;
|
85
|
}
|
86
|
|
87
|
rc = c->cb(cs, op, cmd, argc, argv);
|
88
|
if (rc < 0)
|
89
|
uart_cmd_out(cs, "Error executing command\n\r");
|
90
|
return rc;
|
91
|
}
|
92
|
}
|
93
|
|
94
|
uart_cmd_out(cs, "Unknown command `%s'\n\r", cmd);
|
95
|
return -EINVAL;
|
96
|
}
|
97
|
|
98
|
static void print_list(struct cmd_state *cs)
|
99
|
{
|
100
|
struct cmd *c;
|
101
|
|
102
|
uart_cmd_out(cs, "Supported commands:\r\n");
|
103
|
|
104
|
llist_for_each_entry(c, &cmd_list, list){
|
105
|
const char *help = "";
|
106
|
|
107
|
if (c->help)
|
108
|
help = c->help;
|
109
|
|
110
|
uart_cmd_out(cs, "%s -- %s\n\r", c->cmd, c->help);
|
111
|
}
|
112
|
}
|
113
|
|
114
|
int uart_cmd_char(struct cmd_state *cs, uint8_t ch)
|
115
|
{
|
116
|
int rc;
|
117
|
|
118
|
uart_cmd_out(cs, "%c", ch);
|
119
|
|
120
|
switch (cs->state) {
|
121
|
case ST_IN_CMD:
|
122
|
switch (ch) {
|
123
|
case '=':
|
124
|
cs->state = ST_IN_ARG;
|
125
|
break;
|
126
|
case '?':
|
127
|
uart_cmd_out(cs, "\n\r");
|
128
|
if (cs->cmd.idx == 0)
|
129
|
print_list(cs);
|
130
|
else
|
131
|
rc = handle_cb(cs, CMD_OP_GET, cs->cmd.buf, NULL);
|
132
|
uart_cmd_reset(cs);
|
133
|
break;
|
134
|
case '!':
|
135
|
uart_cmd_out(cs, "\n\r");
|
136
|
rc = handle_cb(cs, CMD_OP_EXEC, cs->cmd.buf, NULL);
|
137
|
uart_cmd_reset(cs);
|
138
|
break;
|
139
|
case ' ':
|
140
|
case '\t':
|
141
|
/* ignore any whitespace */
|
142
|
break;
|
143
|
case '\n':
|
144
|
case '\r':
|
145
|
/* new line always resets buffer */
|
146
|
uart_cmd_reset(cs);
|
147
|
break;
|
148
|
default:
|
149
|
strbuf_append(&cs->cmd, ch);
|
150
|
break;
|
151
|
}
|
152
|
break;
|
153
|
case ST_IN_ARG:
|
154
|
switch (ch) {
|
155
|
case '\r':
|
156
|
uart_cmd_out(cs, "\n");
|
157
|
/* fall through */
|
158
|
case '\n':
|
159
|
rc = handle_cb(cs, CMD_OP_SET, cs->cmd.buf, cs->arg.buf);
|
160
|
uart_cmd_reset(cs);
|
161
|
break;
|
162
|
case ' ':
|
163
|
case '\t':
|
164
|
/* ignore any whitespace */
|
165
|
break;
|
166
|
default:
|
167
|
strbuf_append(&cs->arg, ch);
|
168
|
break;
|
169
|
}
|
170
|
}
|
171
|
|
172
|
if (ch == '\r')
|
173
|
return 1;
|
174
|
|
175
|
return 0;
|
176
|
}
|
177
|
|
178
|
int uart_cmd_out(struct cmd_state *cs, char *format, ...)
|
179
|
{
|
180
|
va_list ap;
|
181
|
|
182
|
va_start(ap, format);
|
183
|
cs->out(format, ap);
|
184
|
va_end(ap);
|
185
|
}
|
186
|
|
187
|
int uart_cmd_reset(struct cmd_state *cs)
|
188
|
{
|
189
|
strbuf_reset(&cs->cmd);
|
190
|
strbuf_reset(&cs->arg);
|
191
|
cs->state = ST_IN_CMD;
|
192
|
|
193
|
uart_cmd_out(cs, "\r\n > ");
|
194
|
|
195
|
return 0;
|
196
|
}
|