forked from embedded2013/rtenv
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathshell.c
334 lines (283 loc) · 8.2 KB
/
shell.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
#include "path_server.h"
#include "serial.h"
#include "syscall.h"
#include "str_util.h"
#include "task.h"
#include "common_define.h"
#define BACKSPACE (127)
#define ESC (27)
#define SPACE (32)
extern struct task_info g_task_info;
static void read_line(char *token, int max_token_chars)
{
int fdin;
char ch[] = {0x00, 0x00};
char last_char_is_ESC = RT_NO;
int curr_char;
fdin = open("/dev/tty0/in", 0);
curr_char = 0;
while(1) {
/* Receive a byte from the RS232 port (this call will
* block). */
read(fdin, &ch[0], 1);
/* Handle ESC case first */
if (last_char_is_ESC == RT_YES) {
last_char_is_ESC = RT_NO;
if (ch[0] == '[') {
/* Direction key: ESC[A ~ ESC[D */
read(fdin, &ch[0], 1);
/* Home: ESC[1~
* End: ESC[2~
* Insert: ESC[3~
* Delete: ESC[4~
* Page up: ESC[5~
* Page down: ESC[6~ */
if (ch[0] >= '1' && ch[0] <= '6') {
read(fdin, &ch[0], 1);
}
continue;
}
}
/* If the byte is an end-of-line type character, then
* finish the string and inidcate we are done.
*/
if (curr_char == (max_token_chars - 2) || \
(ch[0] == '\r') || (ch[0] == '\n')) {
*(token + curr_char) = '\n';
*(token + curr_char + 1) = '\0';
break;
}
else if(ch[0] == ESC) {
last_char_is_ESC = RT_YES;
}
/* Skip control characters. man ascii for more information */
else if (ch[0] < 0x20) {
continue;
}
else if(ch[0] == BACKSPACE) { /* backspace */
if(curr_char > 0) {
curr_char--;
my_printf("\b \b");
}
}
else {
/* Appends only when buffer is not full.
* Include \n\0 */
if (curr_char < (max_token_chars - 3)) {
*(token + curr_char++) = ch[0];
my_puts(ch);
}
}
}
}
/* Tokens */
#define MAX_TOKENS (2)
struct tokens_t
{
int count;
char token[MAX_TOKENS][MAX_MSG_CHARS];
};
typedef struct tokens_t tokens;
/* This is not strtok. Internal Field Separator is SPACE only */
void str_decompose(char *line, tokens *str_tokens)
{
int i = 0;
int curr_pos = 0;
int repeated_space = 0;
int is_quoting = 0;
/* Init */
str_tokens->count = 0;
for(i = 0; i < strlen(line); i++) {
/* End condition always check first */
if (line[i] == '\n') {
/* Is it trailing space? */
if (repeated_space && str_tokens->count > 1) {
str_tokens->count--;
}
else {
str_tokens->token[str_tokens->count][curr_pos] = 0;
str_tokens->count++;
}
return;
}
/* We have new token while token amount is full */
if (str_tokens->count == MAX_TOKENS && line[i] != SPACE) {
return;
}
/* Bypass beginning space */
if (i == 0 && line[0] == SPACE) {
continue;
}
/* Bypass repeated SPACE */
if (line[i - 1] == SPACE && line[i] == SPACE) {
repeated_space = 1;
continue;
}
/* Deal with quoting */
if (line[i] == '"' ) {
is_quoting = !is_quoting;
continue;
}
/* Take char to token */
str_tokens->token[str_tokens->count][curr_pos++] = line[i];
/* Seperate token */
if (line[i] == SPACE && !is_quoting) {
str_tokens->token[str_tokens->count][curr_pos - 1] = 0;
str_tokens->count++;
curr_pos = 0;
repeated_space = 0;
/* Avoid case such as 'ps \n' */
if (line[i + 1] == '\n') {
return;
}
}
}
}
static void ps_cmd(void)
{
int i = 0;
my_printf("\rList process\n");
/* This should not happen actually */
if (!g_task_info.tasks) {
return;
}
/* Start list */
for (i = 0; i < TASK_LIMIT; i++) {
if(g_task_info.tasks[i].status != TASK_IS_EMPTY) {
my_printf("\rTID: %d\tPriority: %d\tStatus: %s\t%s\n",
g_task_info.tasks[i].tid,
g_task_info.tasks[i].priority,
get_task_status(g_task_info.tasks[i].status),
g_task_info.tasks[i].name);
}
}
}
/**************************************/
/* process command */
/**************************************/
typedef void (*cmd_func_t)(tokens *cmd);
struct cmd_t
{
char *name;
char *desc;
char token_num;
cmd_func_t handler;
};
static void demo_task_exit_cmd(tokens *cmd);
static void help_cmd(tokens *cmd);
static void system_cmd(tokens *cmd);
#define CMD(NAME, DESC) { .name = #NAME, \
.desc = DESC, \
.handler = NAME ## _cmd }
typedef struct cmd_t cmd_entry;
static cmd_entry available_cmds[] = {
CMD(ps, "List process"),
CMD(help, "This menu"),
#ifdef USE_SEMIHOST
CMD(system, "Run host command \n" \
"\n\rUsage: system host_command \n"),
#endif
CMD(demo_task_exit, "Demo exits a task")
};
#define CMD_NUM (sizeof(available_cmds)/sizeof(cmd_entry))
/* Helpers */
static int get_cmd_index(char *cmd_name)
{
int i = 0;
if (!cmd_name) {
return CMD_NUM;
}
for (i = 0; i < CMD_NUM; i++) {
if (strncmp(cmd_name, available_cmds[i].name, strlen(available_cmds[i].name)) == 0) {
/* Avoid subset case -> valid cmd: "ps" vs user input: "ps1" */
if (cmd_name[strlen(available_cmds[i].name)] != 0 ) {
return CMD_NUM;
}
break;
}
}
return i;
}
#ifdef USE_SEMIHOST
static void system_cmd(tokens *cmd)
{
if (!cmd || cmd->count != 2) {
return;
}
if (strlen(cmd->token[1]) < MAX_MSG_CHARS - 1 && cmd->token[1][0] != '\n') {
host_system(cmd->token[1], strlen(cmd->token[1]));
}
}
#endif
static void exit_test_task()
{
my_printf("\rtest...sleep 3 second\n");
sleep(3000); /* ms */
my_printf("\rAbout to exit\n");
exit(0);
}
static void demo_task_exit_cmd(tokens *cmd)
{
if (!fork("exit_test_task")) {
setpriority(0, PRIORITY_DEFAULT - 10);
exit_test_task();
}
}
static void help_cmd(tokens *cmd)
{
int i = 0;
/* 1 parameter such as 'help ps' */
if (cmd && cmd->count == 2) {
int cmd_index = 0;
/* Is command valid? */
cmd_index = get_cmd_index(cmd->token[1]);
if (cmd_index == CMD_NUM) {
my_printf("\rCommand not found.\n");
return;
}
my_printf("\r%s\t\t%s\n", available_cmds[cmd_index].name,
available_cmds[cmd_index].desc);
}
else { /* list all commands */
my_printf("\rUse help [cmmand] to get detailed description. ex: help ps\n");
my_printf("\rAvailable Commands:\n");
for (i = 0; i < CMD_NUM; i++) {
my_printf("\r%s\n", available_cmds[i].name);
}
}
}
static void proc_cmd(tokens *cmd)
{
int cmd_index = 0;
my_printf("\n");
/* Is command valid? */
cmd_index = get_cmd_index(cmd->token[0]);
if (cmd_index == CMD_NUM) {
my_printf("\rCommand not found.\n");
return;
}
/* Run cmd */
available_cmds[cmd_index].handler(cmd);
}
void shell_task()
{
char line[MAX_MSG_CHARS];
tokens cmd_tokens;
help_cmd(0);
while (1) {
/* Show prompt */
my_printf("\n\r$ ");
read_line(line, MAX_MSG_CHARS);
/* Skip only \n case */
if (strncmp(line, "\n\0", 2) == 0) {
continue;
}
/* Decompose one line to tokens */
memset((void*)&cmd_tokens, 0x00, sizeof(cmd_tokens));
str_decompose(line, &cmd_tokens);
/* Process command */
if (strlen(cmd_tokens.token[0]) < MAX_MSG_CHARS - 1 && cmd_tokens.token[0][0] != '\n') {
proc_cmd(&cmd_tokens);
}
}
}