shell.c 9.7 KB
Newer Older
1 2 3 4 5 6 7
/*
 * File      : shell.c
 * This file is part of RT-Thread RTOS
 * COPYRIGHT (C) 2006, RT-Thread Development Team
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
8
 * http://www.rt-thread.org/license/LICENSE
9 10 11 12 13 14 15
 *
 * Change Logs:
 * Date           Author       Notes
 * 2006-04-30     Bernard      the first verion for FinSH
 * 2006-05-08     Bernard      change finsh thread stack to 2048
 * 2006-06-03     Bernard      add support for skyeye
 * 2006-09-24     Bernard      remove the code related with hardware
B
bernard.xiong 已提交
16
 * 2010-01-18     Bernard      fix down then up key bug.
17
 * 2010-03-19     Bernard      fix backspace issue and fix device read in shell.
18
 * 2010-04-01     Bernard      add prompt output when start and remove the empty history
19 20 21 22 23 24 25
 */

#include <rtthread.h>
#include <rthw.h>

#include "finsh.h"

S
qemu  
ssslady 已提交
26 27
/*
 * Add by caoxl 2009-10-14
B
bernard.xiong 已提交
28
 *
S
qemu  
ssslady 已提交
29 30 31 32 33 34
 */
#ifdef QEMU_CAOXL
#define  memcpy(a,b,c)	rt_memcpy(a,b,c)
extern char rt_serial_getc(void);
#endif

35 36
#define FINSH_USING_HISTORY

37 38 39 40 41 42 43
#if defined(__CC_ARM)					/* ARMCC compiler */
  #ifdef FINSH_USING_SYMTAB
    extern int FSymTab$$Base;
    extern int FSymTab$$Limit;
    extern int VSymTab$$Base;
    extern int VSymTab$$Limit;
  #endif
44
#elif defined(__ICCARM__)               /* for IAR compiler */
45 46
  #ifdef FINSH_USING_SYMTAB
    #pragma section="FSymTab"
47
    #pragma section="VSymTab"
48
  #endif
49
#elif defined(__GNUC__)
50 51 52 53 54 55
  #ifdef FINSH_USING_SYMTAB
  extern int __fsymtab_start;
  extern int __fsymtab_end;
  extern int __vsymtab_start;
  extern int __vsymtab_end;
  #endif
56
#endif
57 58 59 60 61 62

/* finsh thread */
struct rt_thread finsh_thread;
char finsh_thread_stack[2048];
struct rt_semaphore uart_sem;
rt_device_t finsh_device;
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
#ifdef FINSH_USING_HISTORY
enum input_stat
{
	WAIT_NORMAL,
	WAIT_SPEC_KEY,
	WAIT_FUNC_KEY,
};
#ifndef FINSH_HISTORY_LINES
#define FINSH_HISTORY_LINES 5
#endif
#ifndef FINSH_CMD_SIZE
#define FINSH_CMD_SIZE		80
#endif
char finsh_cmd_history[FINSH_HISTORY_LINES][FINSH_CMD_SIZE];
rt_uint16_t finsh_history_count = 0;
#endif
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95

#if !defined (RT_USING_NEWLIB) && !defined (RT_USING_MINILIBC)
void *memccpy(void *dst, const void *src, int c, size_t count)
{
	char *a = dst;
	const char *b = src;
	while (count--)
	{
		*a++ = *b;
		if (*b==c)
		{
			return (void *)a;
		}

		b++;
	}
	return 0;
96
}
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116

int strcmp (const char *s1, const char *s2)
{
	while (*s1 && *s1 == *s2) s1++, s2++;

	return (*s1 - *s2);
}

#ifdef RT_USING_HEAP
char *strdup(const char *s)
{
	size_t len = strlen(s) + 1;
	char *tmp = (char *)rt_malloc(len);

	if(!tmp) return NULL;

	rt_memcpy(tmp, s, len);
	return tmp;
}
#endif
B
bernard.xiong 已提交
117

118
#if !defined(__CC_ARM) && !defined(__ICCARM__) && !defined(__ICCM16C__)
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
int isalpha( int ch )
{
	return (unsigned int)((ch | 0x20) - 'a') < 26u;
}

int atoi(const char* s)
{
	long int v=0;
	int sign=1;
	while ( *s == ' '  ||  (unsigned int)(*s - 9) < 5u) s++;

	switch (*s)
	{
	case '-': sign=-1;
	case '+': ++s;
	}

	while ((unsigned int) (*s - '0') < 10u)
	{
		v=v*10+*s-'0'; ++s;
	}

	return sign==-1?-v:v;
}

int isprint(unsigned char ch)
{
    return (unsigned int)(ch - ' ') < 127u - ' ';
B
bernard.xiong 已提交
147
}
B
bernard.xiong 已提交
148
#endif
149 150 151 152 153 154 155 156 157 158
#endif

static rt_err_t finsh_rx_ind(rt_device_t dev, rt_size_t size)
{
	/* release semaphore to let finsh thread rx data */
	rt_sem_release(&uart_sem);

	return RT_EOK;
}

159
void finsh_set_device(const char* device_name)
160 161 162 163 164 165 166 167 168 169 170 171
{
	rt_device_t dev = RT_NULL;

	dev = rt_device_find(device_name);
	if (dev != RT_NULL && rt_device_open(dev, RT_DEVICE_OFLAG_RDWR) == RT_EOK)
	{
		if (finsh_device != RT_NULL)
		{
			/* close old finsh device */
			rt_device_close(finsh_device);
		}

172
		finsh_device = dev;
173 174 175 176 177 178 179 180
		rt_device_set_rx_indicate(dev, finsh_rx_ind);
	}
	else
	{
		rt_kprintf("finsh: can not find device:%s\n", device_name);
	}
}

181 182 183 184 185 186 187
void finsh_auto_complete(char* prefix)
{
	extern void list_prefix(char* prefix);

	rt_kprintf("\n");
	list_prefix(prefix);
	rt_kprintf("finsh>>%s", prefix);
188
}
189

190
extern const char* finsh_error_string_table[];
191 192
void finsh_run_line(struct finsh_parser *parser, const char* line)
{
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
	rt_kprintf("\n");
	finsh_parser_run(parser, (unsigned char*)line);

	/* compile node root */
	if (finsh_errno() == 0)
	{
		finsh_compiler_run(parser->root);
	}
	else
	{
		rt_kprintf("%s\n", finsh_error_string(finsh_errno()));
	}

	/* run virtual machine */
	if (finsh_errno() == 0)
	{
		char ch;
		finsh_vm_run();

		ch = (unsigned char)finsh_stack_bottom();
		if (ch > 0x20 && ch < 0x7e)
		{
			rt_kprintf("\t'%c', %d, 0x%08x\n",
				(unsigned char)finsh_stack_bottom(),
				(unsigned int)finsh_stack_bottom(),
				(unsigned int)finsh_stack_bottom());
		}
		else
		{
			rt_kprintf("\t%d, 0x%08x\n",
				(unsigned int)finsh_stack_bottom(),
				(unsigned int)finsh_stack_bottom());
		}
	}
227

228 229 230
    finsh_flush(parser);
}

231 232 233
void finsh_thread_entry(void* parameter)
{
	struct finsh_parser parser;
234
    char line[256], ch;
235
	int  pos ;
236 237 238 239 240
#ifdef FINSH_USING_HISTORY
	enum input_stat stat;
	unsigned short  current_history, use_history;
#endif

241
	pos = 0;
242
	stat = WAIT_NORMAL;
243
	current_history = 0;
244
	use_history = 0;
245
	memset(line, 0, sizeof(line));
246 247

    finsh_init(&parser);
248
	rt_kprintf("finsh>>");
249 250 251

	while (1)
	{
252
		if (rt_sem_take(&uart_sem, RT_WAITING_FOREVER) != RT_EOK) continue;
253

254 255
		/* read one character from device */
		while (rt_device_read(finsh_device, 0, &ch, 1) == 1)
256
		{
257 258 259 260 261 262 263
			#ifdef FINSH_USING_HISTORY
			/*
			 * handle up and down key
			 * up key  : 0x1b 0x5b 0x41
			 * down key: 0x1b 0x5b 0x42
			 */
			if (ch == 0x1b)
264
			{
265 266 267
				stat = WAIT_SPEC_KEY;
				continue;
			}
268

269 270 271 272 273 274 275 276 277
			if ((stat == WAIT_SPEC_KEY) && (ch == 0x5b))
			{
				if (ch == 0x5b)
				{
					stat = WAIT_FUNC_KEY;
					continue;
				}
				stat = WAIT_NORMAL;
			}
278

279 280 281
			if (stat == WAIT_FUNC_KEY)
			{
				stat = WAIT_NORMAL;
B
bernard.xiong 已提交
282

283 284 285 286 287
				if (ch == 0x41) /* up key */
				{
					/* prev history */
					if (current_history > 0)current_history --;
					else
288
					{
289
						current_history = 0;
290 291 292
						continue;
					}

293 294 295 296 297 298 299 300 301 302 303 304
					/* copy the history command */
					memcpy(line, &finsh_cmd_history[current_history][0],
						FINSH_CMD_SIZE);
					pos = strlen(line);
					use_history = 1;
				}
				else if (ch == 0x42) /* down key */
				{
					/* next history */
					if (current_history < finsh_history_count - 1)
						current_history ++;
					else
305
					{
306 307 308 309 310 311
						/* set to the end of history */
						if (finsh_history_count != 0)
						{
							current_history = finsh_history_count - 1;
						}
						else continue;
312 313
					}

314 315 316 317 318
					memcpy(line, &finsh_cmd_history[current_history][0],
						FINSH_CMD_SIZE);
					pos = strlen(line);
					use_history = 1;
				}
319

320 321 322 323 324
				if (use_history)
				{
					rt_kprintf("\033[2K\r");
					rt_kprintf("finsh>>%s", line);
					continue;
325 326
				}
			}
327
			#endif
328

329 330
			/* handle tab key */
			if (ch == '\t')
331
			{
332 333 334 335 336 337 338 339 340 341
				/* auto complete */
				finsh_auto_complete(&line[0]);
				/* re-calculate position */
				pos = strlen(line);
				continue;
			}
			/* handle backspace key */
			else if (ch == 0x7f || ch == 0x08)
			{
				if (pos != 0)
342
				{
343
					rt_kprintf("%c %c", ch, ch);
344
				}
345 346 347 348
				if (pos <= 0) pos = 0;
				else pos --;
				line[pos] = 0;
				continue;
349
			}
350 351
			/* handle end of line, break */
			else if (ch == 0x0d || ch == 0x0a)
352
			{
353 354
				/* change to ';' and break */
				line[pos] = ';';
355

356
				#ifdef FINSH_USING_HISTORY
357
				if ((use_history == 0) && (pos != 0))
358 359 360 361 362 363 364 365 366 367 368 369 370
				{
					/* push history */
					if (finsh_history_count >= FINSH_HISTORY_LINES)
					{
						/* move history */
						int index;
						for (index = 0; index < FINSH_HISTORY_LINES - 1; index ++)
						{
							memcpy(&finsh_cmd_history[index][0],
								&finsh_cmd_history[index + 1][0], FINSH_CMD_SIZE);
						}
						memset(&finsh_cmd_history[index][0], 0, FINSH_CMD_SIZE);
						memcpy(&finsh_cmd_history[index][0], line, pos);
371

372 373 374 375 376 377 378
						/* it's the maximum history */
						finsh_history_count = FINSH_HISTORY_LINES;
					}
					else
					{
						memset(&finsh_cmd_history[finsh_history_count][0], 0, FINSH_CMD_SIZE);
						memcpy(&finsh_cmd_history[finsh_history_count][0], line, pos);
379

380 381 382 383 384
						/* increase count and set current history position */
						finsh_history_count ++;
					}
				}
				current_history = finsh_history_count;
385 386 387 388
				#endif

				if (pos != 0) finsh_run_line(&parser, line);
				else rt_kprintf("\n");
389

390 391 392
				rt_kprintf("finsh>>");
				memset(line, 0, sizeof(line));
				pos = 0;
393

394
				break;
395 396
			}

397 398 399 400 401 402 403 404
			/* it's a large line, discard it */
			if (pos >= 256) pos = 0;

			/* normal character */
			line[pos] = ch; ch = 0;
			rt_kprintf("%c", line[pos++]);
			use_history = 0; /* it's a new command */
		} /* end of device read */
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
	}
}

void finsh_system_function_init(void* begin, void* end)
{
	_syscall_table_begin = (struct finsh_syscall*) begin;
	_syscall_table_end = (struct finsh_syscall*) end;
}

void finsh_system_var_init(void* begin, void* end)
{
	_sysvar_table_begin = (struct finsh_sysvar*) begin;
	_sysvar_table_end = (struct finsh_sysvar*) end;
}

/* init finsh */
421
void finsh_system_init(void)
422 423 424 425 426 427 428 429 430 431 432 433 434
{
	rt_sem_init(&uart_sem, "uart", 0, 0);

#ifdef FINSH_USING_SYMTAB
#ifdef __CC_ARM                 /* ARM C Compiler */
	finsh_system_function_init(&FSymTab$$Base, &FSymTab$$Limit);
	finsh_system_var_init(&VSymTab$$Base, &VSymTab$$Limit);
#elif defined (__ICCARM__)      /* for IAR Compiler */
    finsh_system_function_init(__section_begin("FSymTab"),
                               __section_end("FSymTab"));
    finsh_system_var_init(__section_begin("VSymTab"),
                          __section_end("VSymTab"));
#elif defined (__GNUC__)        /* GNU GCC Compiler */
435 436
	finsh_system_function_init(&__fsymtab_start, &__fsymtab_end);
	finsh_system_var_init(&__vsymtab_start, &__vsymtab_start);
437 438 439
#endif
#endif

440
#if RT_THREAD_PRIORITY_MAX == 8
441 442 443 444
	rt_thread_init(&finsh_thread,
		"tshell",
		finsh_thread_entry, RT_NULL,
		&finsh_thread_stack[0], sizeof(finsh_thread_stack),
445 446 447 448 449 450 451 452 453
		5, 10);
#else
	rt_thread_init(&finsh_thread,
		"tshell",
		finsh_thread_entry, RT_NULL,
		&finsh_thread_stack[0], sizeof(finsh_thread_stack),
		20, 10);
#endif

454 455
	rt_thread_startup(&finsh_thread);
}