import of upstream version 1.17
[mw/micromonitor-lm32.git] / umon_main / target / common / chario.c
1 /* chario.c:
2  *      This code supports some basic character io functionality.
3  *
4  *      General notice:
5  *      This code is part of a boot-monitor package developed as a generic base
6  *      platform for embedded system designs.  As such, it is likely to be
7  *      distributed to various projects beyond the control of the original
8  *      author.  Please notify the author of any enhancements made or bugs found
9  *      so that all may benefit from the changes.  In addition, notification back
10  *      to the author will allow the new user to pick up changes that may have
11  *      been made by other users after this version of the code was distributed.
12  *
13  *      Note1: the majority of this code was edited with 4-space tabs.
14  *      Note2: as more and more contributions are accepted, the term "author"
15  *                 is becoming a mis-representation of credit.
16  *
17  *      Original author:        Ed Sutter
18  *      Email:                          esutter@lucent.com
19  *      Phone:                          908-582-2351
20  */
21 #include "config.h"
22 #include "cpuio.h"
23 #include "genlib.h"
24 #include "stddefs.h"
25 #include "timer.h"
26 #include "ether.h"
27 #include "fbi.h"
28
29 #define CTLC    0x03    /* control-c */
30
31 int rawmode, ConsoleBaudRate;
32
33 /* extWatchDog():
34  * This function pointer is used by the application to override the
35  * monitor's configured watchdog functionality.  Refer to config.h
36  * in umon_ports/template for more information on the WATCHDOG macro.
37  */
38 #ifdef WATCHDOG_ENABLED
39 int (*remoteWatchDog)(void);
40 #endif
41
42 /* remotexxxx() function pointers:
43  * These function pointers provide the application with the ability to
44  * override the monitor's default putchar/getchar/gotachar functions.
45  * See comments above InitRemoteIO() function below for more info.
46  */
47 int     (*remoterawon)(void);
48 int (*remoterawoff)(void);
49 int     (*remoteputchar)(int);
50 int (*remotegetchar)(void);
51 int (*remotegotachar)(void);
52
53 /* putchar():
54  *      Output a character to the stdout RS232 port.
55  */
56 int
57 putchar(char c)
58 {
59         /* If the remoteputchar function pointer is non-zero, then we
60          * assume that the default putchar function has been overridden
61          * by some overlaying application using mon_com(CHARFUNC_PUTCHAR,),
62          * so we use that redefined function instead...
63          */
64         if (remoteputchar) {
65                 remoteputchar(c);
66                 return((int)c);
67         }
68
69         if (rawmode) {
70                 target_putchar(c);
71                 fbi_putchar(c);
72                 return((int)c);
73         }
74
75         /* If redirection is active, the redirect the character to a file
76          * in TFS.  Note that if INCLUDE_REDIRECT is 0, then this function
77          * is NULL (see genlib.h).
78          */
79         RedirectCharacter(c);
80
81         /* Call the target-specific function that puts the character out on
82          * the console port (precede '\n' with '\r').
83          * For each call to target_putchar(), call SendIPMonChar so that if
84          * this output is generated by moncmd, it will be sent back to the
85          * moncmd client.  Note that if INCLUDE_ETHERNET is 0, then the
86          * function SendIPMonChar is NULL (see ether.h).
87          */
88         if (c == '\n') {
89                 SendIPMonChar('\r',0);
90                 fbi_putchar('\r');
91                 target_putchar('\r');
92         }
93         SendIPMonChar(c,0);
94         target_putchar(c);
95         fbi_putchar(c);
96         WATCHDOG_MACRO;
97         return((int)c);
98 }
99
100 int 
101 getchar(void)
102 {
103         /* If the remotegetchar function pointer is non-zero, then we
104          * assume that the default getchar function has been overridden
105          * by some overlaying application using mon_com(CHARFUNC_GETCHAR,),
106          * so we use that redefined function instead...
107          */
108     if (remotegetchar)
109         return(remotegetchar());
110     
111         while(!gotachar()) {
112                 /* While waiting for an incoming character, call pollethernet()
113                  * to process any incoming packets.  Note that if INCLUDE_ETHERNET
114                  * is 0 in config.h, then this function is NULL (see ether.h).
115                  */
116                 WATCHDOG_MACRO;
117         pollethernet();
118         }
119
120         return(target_getchar());
121 }
122
123 int
124 gotachar(void)
125 {
126         /* If the remotegotachar function pointer is non-zero, then we
127          * assume that the default gotachar function has been overridden
128          * by some overlaying application using mon_com(CHARFUNC_GOTACHAR,),
129          * so we use that redefined function instead...
130          */
131     if (remotegotachar)
132         return(remotegotachar());
133     
134         fbi_cursor();
135         WATCHDOG_MACRO;
136         return(target_gotachar());
137 }
138
139 /* flush_console_out():
140  * Call this function to wait for the console UART to flush all outgoing
141  * characters.  Note that this function has a timeout in the loop.
142  */
143 void
144 flush_console_out(void)
145 {
146         int timeout = 0;
147
148     if (remoteputchar)
149         return;
150
151         while(timeout++ < 50000) {
152                 if (target_console_empty()) {
153                         monDelay(10);
154                         break;
155                 }
156         }
157 }
158
159 /* flush_console_in(void):
160  * While there is input queued up from the console, 
161  * flush it to the bit bucket...
162  */
163 void
164 flush_console_in(void)
165 {
166         while(gotachar())
167                 getchar();
168 }
169
170
171 /* rawon() & rawoff():
172  * Used primarily by xmodem.  When xmodem runs, it must be assured that
173  * the interface is in RAW mode.  For the case of the monitor alone, it
174  * will always be in a raw mode.  These functions are primarily for use
175  * when an application has re-loaded the serial driver and may have put
176  * it in a non-raw mode.  The mon_com() calls CHARFUNC_RAWMODEON and
177  * CHARFUNC_RAWMODEOFF establish these pointers.
178  */
179 void
180 rawon(void)
181 {
182     if (remoterawon)
183         remoterawon();
184         rawmode = 1;
185 }
186
187 void
188 rawoff(void)
189 {
190     if (remoterawoff)
191         remoterawoff();
192         rawmode = 0;
193 }
194
195 /* puts() & putstr():
196  * Two string-output functions.  
197  * puts: normal "puts" as is available in standard c libs.
198  * putstr: same as "puts", but no ending newline.
199  */
200
201 void
202 putstr(char *string)
203 {
204         while(*string) {
205                 putchar(*string);
206                 string++;
207         }
208 }
209
210 void
211 puts(char *string)
212 {
213         putstr(string);
214         putchar('\n');
215 }
216
217
218 /* getfullline():
219  * Basic line retrieval; but with a few options...
220  * This function is accessed through the getline_xx functions
221  * below.
222  * Args...
223  *      buf:     pointer to buffer to be used to place the incoming characters.
224  *  max:         size of the buffer.
225  *  ledit:       if set, then allow the line-editor to be used if ESC is input.
226  *  timeout: if positive, then after 'timeout' number of seconds waiting
227  *                per character, giveup.
228  *           if negative, then after 'timeout' number of seconds waiting
229  *                total, giveup.
230  *           if zero, then wait forever.
231  *  prefill: if set, prefill the buffer with that string and show the user.
232  *  echo:    if set, characters are echoed as they are entered.
233  */
234 int
235 getfullline(char *buf,int max,int ledit, int timeout,char *prefill, int echo)
236 {
237         char    *base;
238         struct  elapsed_tmr tmr;
239         static  unsigned char  crlf;
240         int             tot, idx, cumulativetimeout;
241
242         cumulativetimeout = 0;
243         tot = idx = 0;
244         base = buf;
245         max -= 1;               /* Make sure there is space for the null terminator. */
246
247         if (prefill) {
248                 strcpy(base,prefill);
249                 tot = strlen(prefill);
250                 putstr(prefill);
251                 buf += tot;
252                 idx = tot;
253         }
254
255         /* If the timeout parameter is negative, then assume that this is
256          * to be run with a cumulative timeout rather than a timeout that
257          * is re-started after each character...
258          */
259         if (timeout < 0) { 
260                 cumulativetimeout = 1;
261                 timeout = abs(timeout);
262         }
263
264         for(;idx<max;idx++) {
265                 if (timeout > 0) {
266                         startElapsedTimer(&tmr,timeout);
267                         while(!msecElapsed(&tmr)) {
268                                 if (gotachar())
269                                         break;
270                                 pollethernet();
271                         }
272                         if (cumulativetimeout)
273                                 timeout = msecRemaining(&tmr);
274
275                         if (ELAPSED_TIMEOUT(&tmr)) {
276                                 *buf = 0;
277                                 return(-1);     /* Return negative to indicate timeout */
278                         }
279                 }
280                 if (cumulativetimeout && timeout == 0) {
281                         *buf = 0;
282                         return(-1);
283                 }
284
285                 *buf = (char)getchar();
286                 if (!*buf) {
287                         idx--;
288                         continue;
289                 }
290 #if INCLUDE_LINEEDIT
291                 if ((*buf == 0x1b) && (ledit)) {
292                         (void)line_edit(base);
293                         break;
294                 }
295                 else
296 #endif
297                 {
298                         if ((*buf == '\r') || (*buf == '\n')) {
299                                 if ((crlf) && (*buf != crlf)) {
300                                         crlf = 0;
301                                         continue;
302                                 }
303                                 puts("\r");
304                                 crlf = *buf;
305                                 *buf = 0;
306                                 break;
307                         }
308                         if (*buf == '\b') {
309                                 if (tot) {
310                                         idx -= 2;
311                                         buf--; 
312                                         tot--;
313                                         if (echo)
314                                                 putstr("\b \b");
315                                 }
316                         }
317                         else if (*buf == CTLC) {
318                                 puts("^C");
319                                 *base = 0;
320                                 return(0);
321                         }
322                         else {
323                                 if (echo)
324                                         putchar(*buf);
325                                 tot++; 
326                                 buf++;
327                         }
328                         crlf = 0;
329                 }
330         }
331         if (idx == max) {
332                 printf((char *)"\007\nInput too long (exceeds %d bytes).\n",max);
333                 *buf = 0;
334                 return(0);
335         }
336 #if INCLUDE_LINEEDIT
337         if (ledit)
338                 historylog(base);
339 #endif
340         return(strlen(base));
341 }
342
343 int
344 getline(char *buf, int max, int ledit)
345 {
346         return(getfullline(buf,max,ledit,0,0,1));
347 }
348
349 int
350 getline_t(char *buf, int max, int timeout)
351 {
352         return(getfullline(buf,max,0,timeout,0,1));
353 }
354
355 int
356 getline_p(char *buf, int max, int ledit, char *prefill)
357 {
358         return(getfullline(buf,max,ledit,0,prefill,1));
359 }
360
361 /* getpass():
362  */
363 #if INCLUDE_USRLVL
364 char *
365 getpass(char *prompt,char *buf,int max, int timeout)
366 {
367         putstr(prompt);
368         if (getfullline(buf,max,0,timeout*1000,0,0) == -1)
369                 putchar('\n');
370         return(buf);
371 }
372 #endif
373
374 /* getbytes():
375  *      Similar to gets() except that the caller specifies the number
376  *      of characters and whether or not to block.
377  *  If the copy to the buffer fails, abort and return the current
378  *  count.
379  */
380
381 int
382 getbytes(char *buf,int cnt,int block)
383 {
384         int     i;
385         volatile char *bp;
386         char c;
387
388         bp = (volatile char *)buf;
389
390         for(i=0;i<cnt;i++) {
391                 if (!block && !gotachar())
392                         break;
393                 c = (char)getchar();
394                 *bp = c;
395                 if (*bp != c)
396                         break;
397                 bp++;
398         }
399         return(i);
400 }
401
402 /* getbytes_t():
403  *      Similar to getbytes() except that the caller specifies the allowed
404  *  timeout between two consecutive bytes received.
405  *  If the copy to the buffer fails, or timeout occures, abort and return
406  *      the current count.
407  */
408
409 int
410 getbytes_t(char *buf,int cnt,int timeout)
411 {
412         int     i;
413         struct elapsed_tmr tmr;
414         volatile char *bp;
415         char c;
416
417         bp = (volatile char *)buf;
418
419         for(i=0;i<cnt;i++) {
420                 if (!gotachar()) {
421                         startElapsedTimer(&tmr,timeout);
422                         while(!gotachar() && !msecElapsed(&tmr));
423                         if (!gotachar())
424                                 break;
425                 }
426                 c = (char)getchar();
427                 *bp = c;
428                 if (*bp != c)
429                         break;
430                 bp++;
431         }
432         return(i);
433 }
434
435 int
436 putbytes(char *buf, int cnt)
437 {
438         char *end;
439
440         end = buf + cnt;
441
442         while(buf < end) {
443                 putchar(*buf++);
444         }
445         return(cnt);
446 }
447
448 int
449 askuser(char *msg)
450 {
451         int     yes, len;
452
453 #if INCLUDE_MONCMD
454         /* If command was issued from UDP (i.e. moncmd), then
455          * immediately return 1...
456          */
457         if (IPMonCmdActive)
458                 return(1);
459 #endif
460
461         putstr(msg);
462         len = strlen(msg);
463         switch((char)getchar()) {
464                 case ' ':
465                 case 'y':
466                 case '\r':
467                 case '\n':
468                         yes = 1;
469                         break;
470                 default:
471                         yes = 0;
472                         break;
473         }
474         while(len) {
475                 putstr("\b \b");
476                 len--;
477         }
478         return(yes);
479 }
480
481 int
482 More(void)
483 {
484         return(askuser((char *)"more?"));
485 }
486
487 int
488 hitakey(void)
489 {
490         return(askuser((char *)"hit any key to continue..."));
491 }
492
493 /* RemoteIO functions:
494  * The idea of "remote io" is to allow the monitor commands to still
495  * run when the application has taken over the system.  The monitor's
496  * connection to the serial port is a simple polled interface.  When 
497  * the application comes up, it is very likely that it will overlay a
498  * new driver onto the serial port.  If this happens, and the user at
499  * the console interface of the application wants to execute a monitor
500  * command, then the monitor's putchar/getchar/gotachar functions must
501  * use functions that are part of the application.  These remote io
502  * function pointers, if set, will point to those functions.
503  */
504
505 void
506 InitRemoteIO(void)
507 {
508         /* Null out the remote put/getchar functions. */
509         remoterawon = 0;
510         remoterawoff = 0;
511         remoteputchar = 0;
512         remotegetchar = 0;
513         remotegotachar = 0;
514 }