📄 logterm.c
字号:
/* -*-C-*- * * $Revision: 1.1 $ * $Author: rivimey $ * $Date: 1999/03/11 11:54:02 $ * * Copyright (c) 1997 Advanced RISC Machines Limited. * All Rights Reserved. * * Project: ANGEL * * Title: Debug interface via Serial writes to 16c552 serial port B. */#include <string.h>#if DEBUG == 1 && (!defined(MINIMAL_ANGEL) || MINIMAL_ANGEL == 0)#include "channels.h"#include "devconf.h"#include "platform.h"#include "logging.h"#include "logging/logterm.h"#include "serlock.h"#include "serring.h"#include "debug.h"#include "support.h"#include "disass.h"#define SAVEBUFSIZE 2048 /* max #words in save buffer -- min 6 words/message */#define MAXARGS 32 /* max number of distinct args on cmd line */#define CMDBUFSIZE 128 /* max number of characters on command line */#define OUTPUTBUFSIZE 64 /* number of buffered characters from message before flush */#ifndef UNUSED#define UNUSED(x) (0 ? (x) = (x) : 0)#endifstatic unsigned long msgsavebuf[SAVEBUFSIZE];static struct LogSaveBuffer savebuf;static char log_commandbuf[CMDBUFSIZE];static int log_cursor = 0;static WarnLevel logterm_level;static char logterm_buf[OUTPUTBUFSIZE];static char *logterm_pos;static char *logterm_end;static int log_tracing = TRUE;static int log_deferredprompt = FALSE;static int log_buflock = FALSE;static int log_cmdlock = FALSE;/* static void setupsave(void); */void log_emitch(char ch);void log_emitstr(char *str);static void log_output(int enable);static void log_processchar(char ch, unsigned int empty_stack);static int log_dump(int argc, char **argv);static int log_echo(int argc, char **argv);static int log_ver(int argc, char **argv);static int log_help(int argc, char **argv);static int log_trace(int argc, char **argv);static int log_go(int argc, char **argv);static int log_restart(int argc, char **argv);int log_pause(int argc, char **argv);static int log_stat(int argc, char **argv);static int log_task(int argc, char **argv);static int log_level(int argc, char **argv);#ifdef HAVE_DISASSstatic int log_list(int argc, char **argv);#endifstatic int log_format(int argc, char **argv);static struct { char *str; int (*pfn)(int argc, char **argv); char *desc, *helpstr;} log_cmds[] ={ /* These must be kept in sorted order by name */ { "dump", log_dump, "Dump\n", "syntax: dump <start addr> [ <end addr> | +<len> ]\n" }, { "echo", log_echo, "Echo\n", "syntax: echo <words>\n" }, { "format",log_format,"Show / set the per-line format string\n", "syntax: format [<new string>]\n" }, { "go", log_go, "Undo pause; reenable ints\n", "syntax: go\n" }, { "help", log_help, "Command help\n", "syntax: help [command]\n" }, { "level", log_level, "Set the minimum log level displayed.\n", "syntax: level [info|warn|err]\n" },#ifdef HAVE_DISASS { "list", log_list, "Disassemble instructions from memory.\n", "syntax: list addr1 [addr2 | +len]\n" },#endif { "pause", log_pause, "Pause Angel; disable ints\n", "syntax: pause\n" }, { "restart", log_restart,"Reboot Angel, optionally specifying restart addr.\n", "syntax: reboot [address]\n" }, { "stat", log_stat, "Display internal statistics info\n", "syntax: stat [packagename]\n" " packages: serpkt\n" }, { "task", log_task, "Display internal task details\n", "syntax: task - general scheduler details\n" " task list - list all known task contexts\n" " task log <n> - display <n> entries in task event log\n" " task rb <name> - print global regblock <name> from:\n" " Intr,Desrd,SWI,Abort,Undef,Yield,Fatal,\n" " task tq <n> - display task queue entry <n>\n" }, { "trace", log_trace, "Enable/disable tracing or display trace buffer\n", "syntax: trace -- display current settings\n" " trace <n> -- show <n> lines of buffer\n" " trace <n> -- show <n> lines of buffer\n" " trace on | off -- enable/disable run-time trace\n" }, { "ver", log_ver, "Display Angel version info\n", "syntax: ver\n" },};static const int log_ncmds = sizeof(log_cmds)/sizeof(log_cmds[0]);/* * NT's HyperTerminal needs CRLF, not just LF! */#define LOGTERM_ADD_CR_TO_LF 1#pragma no_check_stack#include "banner.h"#define LOGONMESSAGE "\n\n" ANGEL_BANNER "Type 'help' for more info.\n\n"#define PROMPT "% "/* * macros to control Interrupt Enable Register in various sensible ways */#ifdef DEBUG_WITHINTERRUPTS#define st16c552_EnableTxInterrupt(u) (IER_set((u), TxReadyInt))#define st16c552_DisableTxInterrupt(u) (IER_clr((u), TxReadyInt))#define st16c552_EnableRxInterrupt(u) (IER_set((u), RxReadyInt))#define st16c552_DisableRxInterrupt(u) (IER_clr((u), RxReadyInt))#endif/* * prefix for lines not at start of message -- see stuff in putchar too */#define PREFIXLEN 6/* * prototypes *//* * Function: stoi * Purpose: string to integer conversion; like atoi but doesn't pull in * the rest of the c library! * * Pre-conditions: none. * * Params: * Input: s - pointer to (base-10) number in ASCII * * Output: e - pointer to last character converted * * Returns: number converted */static int stoi(char *s, char **e){ int i, sign = 0, base = 10; while(*s == ' ') s++; switch(*s) { case '-': sign = -1; s++; break; case '0': if (s[1] == 'x') { base = 16; s+=2; } break; case '+': s++; sign = 1; break; default: sign = 1; break; } i = 0; if (base == 10) { while(*s >= '0' && *s <= '9') { i = (i * 10) + (*s - '0'); s++; } } else { while((*s >= '0' && *s <= '9') || (*s >= 'a' && *s <= 'f') || (*s >= 'A' && *s <= 'F')) { if (*s >= 'a') i = (i * 16) + (*s - 'a' + 10); else if (*s >= 'A') i = (i * 16) + (*s - 'A' + 10); else i = (i * 16) + (*s - '0'); s++; } } if (sign < 0) i = -i; *e = s; return i;}void logterm_flushbuf(void);/* * Function: logterm_Initialise * Purpose: * * Pre-conditions: none. * * Params: * Input: * * Returns: 0. *//* REMEMBER: This routine gets called VERY EARLY!! */bool logterm_Initialise(void){ logserial_Reset(LOGTERM_PORT, BAUDVALUE) ; /* * output is polled, but input is interrupt-driven. */#ifdef DEBUG_WITHINTERRUPTS st16c552_DisableTxInterrupt(serchip); st16c552_EnableRxInterrupt(serchip);#endif /* * print a logon banner to say we're here! */ log_emitstr(LOGONMESSAGE); log_emitstr(PROMPT); log_deferredprompt = FALSE; log_tracing = TRUE; log_setupsave(&savebuf, msgsavebuf, SAVEBUFSIZE); log_set_logging_options(WL_SAVEMSG|WL_PRINTMSG); log_set_log_id(LOG_ALWAYS, 1); /* this works because it's polled input... interrupts * are disabled in this code */ log_pause(0,0); return 0;}struct LogSaveBuffer *log_getlogtermbuf(void){ return &savebuf;}bool logterm_PreWarn(WarnLevel level){ /* * set up the buffer pointers... reset in flushbuf */ logterm_pos = logterm_buf; logterm_end = (logterm_buf + sizeof(logterm_buf) - 1); logterm_level = level; return TRUE;}void logterm_flushbuf(void){ char *p; p = logterm_buf; while(p < logterm_pos) { log_emitch(*p++); } logterm_pos = logterm_buf; logterm_end = logterm_buf + sizeof(logterm_buf) - 1;}int logterm_PutChar(char c){ if (logterm_pos >= logterm_end) logterm_flushbuf(); *logterm_pos++ = c; return 0;}void logterm_PutString(char *str){ while(*str) { logterm_PutChar(*str++); }}void logterm_PostWarn(unsigned int len){ IGNORE(len); if (logterm_pos > logterm_buf) logterm_flushbuf();}/* * Show a number nlines of messages from the trace buffer, working * back from the current insert position. * * This is done by starting at the insert position and using the * count value (which is at 'insert' - 1) to skip backwards through * the buffer until either the oldest data is reached or the required * number of lines is found. * * Then work forward, calling log_logprint() to print the text. * */static void log_showitems(struct LogSaveBuffer *sb, int nlines){ int count, message_start = sb->message; unsigned long *ptr = sb->current; log_printf("showitems: sb = %x, lins %d, ptr = %x; *ptr = %x\n", sb, nlines, ptr, *ptr); if (ptr == 0 || *ptr == 0) /* nothing to do */ return; ptr--; /* normally, savebufinsert points at next free slot */ /* * while we haven't got to the start point -- either the start of * data, or the item we want to start with, or the oldest item in * the buffer is reached, skip back from the insert point. * * Note: 'start of data' and 'oldest' are differently encoded -- start * of data is indicated by a zero count, written when the buffer is * set up. 'oldest' is reached when the current pointer is larger * than the insert pointer, and (ptr - count) is less. */ count = nlines; while(count > 0 && *ptr != 0) { log_printf("showitems: count %d, mess %d\n", count, message_start); /* * got to oldest; no more (complete) messages available. */ if (ptr >= sb->current && (ptr - (*ptr & 0xff)) < sb->current) break; /* * if this message marks the end of a line (flagged by the top * bits of the word being set), decrement the message number too. */ if (*ptr & ~0xff) { message_start--; count--; } /* skip one more back, wrapping around the beginning. */ ptr -= (*ptr & 0xff); if (ptr < sb->start) ptr += sb->size; } log_printf("showitems: count %d, ptr %x\n", count, ptr ); /* * now run forward, printing each line from the data in the buffer. Of * course, pointer values are printed from memory, and so may be incorrect * if the program changed that memory in the meantime.... */ count = nlines; while(count > 0) { log_logprint(message_start, ptr); if (*ptr & ~0xff) { message_start++; count--; } /* skip one more forward, wrapping around the beginning. */ ptr += *ptr; if (ptr >= sb->end) ptr -= sb->size; } log_printf("showitems: done\n" );}void log_emitch(char ch){ int status ;#ifdef LOGTERM_ADD_CR_TO_LF if (ch == '\n') { do { status = LOG_GET_STATUS(LOGTERM_PORT) ; } while (!LOG_TX_READY(status)) ; LOG_PUT_CHAR(LOGTERM_PORT, '\r') ; }#endif do { status = LOG_GET_STATUS(LOGTERM_PORT) ; } while (!LOG_TX_READY(status)) ; LOG_PUT_CHAR(LOGTERM_PORT, ch) ;}void log_emitstr(char *str){ while(*str) { log_emitch(*str++); }}/**************************************************************************//* Command Interpreter *//**************************************************************************//* * Function: log_stat * Purpose: Print status report; eventually, this should be able to, for * example, print the number of packets sent, or CRC errors under ADP, * or whatever else. Needs more work! * * Pre-conditions: none. * * Params: * Input: argc, argv - "main" argc/argv pair containing args. argv[0] * is name of command (i.e. "stat"). * * Returns: 0. */extern struct StatInfo spk_stat_info[];extern struct StatInfo intr_stat_info[];extern struct StatInfo task_stat_info[];static int log_stat(int argc, char **argv){ struct StatInfo *p = NULL; char *h = "known modules: serpkt, intr, task\n"; if (argc < 2) { log_emitstr("stat: no module name given\n"); log_emitstr(h); return 0; } if (__rt_strcmp(argv[1], "serpkt") == 0) { p = spk_stat_info; } else if (__rt_strcmp(argv[1], "intr") == 0) { p = intr_stat_info; } else if (__rt_strcmp(argv[1], "task") == 0) { p = task_stat_info; } if (p) { while(p->format != NULL) { int l; logterm_PreWarn(WL_INFO); l = log_printf(p->format, *p->param); logterm_PostWarn(l); p++; } } else { log_emitstr("stat: unknown module name\n"); log_emitstr(h); } return 0;}/* * Function: log_level * Purpose: * * Pre-conditions: none. * * Params: * Input: argc, argv - "main" argc/argv pair containing args. argv[0] * is name of command (i.e. "level"). * * Returns: 0. */static int log_level(int argc, char **argv){ WarnLevel lvl; if (argc == 1) { lvl = log_get_log_minlevel(); switch(lvl) { case WL_INFO: log_emitstr("level: info\n"); break; case WL_WARN: log_emitstr("level: warn\n"); break; case WL_ERROR: log_emitstr("level: error\n"); break; } } else if (argc == 2) { if (argv[1][0] == 'i') { log_set_log_minlevel(WL_INFO); } else if (argv[1][0] == 'w') { log_set_log_minlevel(WL_WARN); } else if (argv[1][0] == 'e') { log_set_log_minlevel(WL_ERROR); } else log_emitstr("level: unknown level name\n"); } else { log_emitstr("level: bad syntax\n"); } return 0;}/* * Function: log_go
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -