Revision ba516b61 os/core/src/aos_shell.c

View differences:

os/core/src/aos_shell.c
18 18

  
19 19
#include <aos_shell.h>
20 20

  
21
#if (AMIROOS_CFG_SHELL_ENABLE == true)
21 22
#include <aos_debug.h>
22 23
#include <aos_time.h>
23 24
#include <aos_system.h>
......
25 26
#include <string.h>
26 27
#include <aos_thread.h>
27 28

  
29

  
30

  
31
/**
32
 * @brief   Event mask to be set on OS related events.
33
 */
34
#define AOS_SHELL_EVENTMASK_OS                  EVENT_MASK(0)
35

  
36
/**
37
 * @brief   Event mask to be set on a input event.
38
 */
39
#define AOS_SHELL_EVENTMASK_INPUT               EVENT_MASK(1)
40

  
41
/**
42
 * @brief   Implementation of the BaseAsynchronous write() method (inherited from BaseSequentialStream).
43
 */
44
static size_t _channelwrite(void *instance, const uint8_t *bp, size_t n)
45
{
46
  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_OUTPUT_ENABLED) {
47
    return streamWrite(((AosShellChannel*)instance)->iochannel->asyncchannel, bp, n);
48
  } else {
49
    return 0;
50
  }
51
}
52

  
53
/**
54
 * @brief   Implementation of the BaseAsynchronous read() method (inherited from BaseSequentialStream).
55
 */
56
static size_t _channelread(void *instance, uint8_t *bp, size_t n)
57
{
58
  return streamRead(((AosShellChannel*)instance)->iochannel->asyncchannel, bp, n);
59
}
60

  
61
/**
62
 * @brief   Implementation of the BaseAsynchronous put() method (inherited from BaseSequentialStream).
63
 */
64
static msg_t _channelput(void *instance, uint8_t b)
65
{
66
  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_OUTPUT_ENABLED) {
67
    return streamPut(((AosShellChannel*)instance)->iochannel->asyncchannel, b);
68
  } else {
69
    return MSG_RESET;
70
  }
71
}
72

  
73
/**
74
 * @brief   Implementation of the BaseAsynchronous get() method (inherited from BaseSequentialStream).
75
 */
76
static msg_t _channelget(void *instance)
77
{
78
  return streamGet(((AosShellChannel*)instance)->iochannel->asyncchannel);
79
}
80

  
81
/**
82
 * @brief   Implementation of the BaseAsynchronous putt() method.
83
 */
84
static msg_t _channelputt(void *instance, uint8_t b, systime_t time)
85
{
86
  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_OUTPUT_ENABLED) {
87
    return chnPutTimeout(((AosShellChannel*)instance)->iochannel->asyncchannel, b, time);
88
  } else {
89
    return MSG_RESET;
90
  }
91
}
92

  
93
/**
94
 * @brief   Implementation of the BaseAsynchronous gett() method.
95
 */
96
static msg_t _channelgett(void *instance, systime_t time)
97
{
98
  return chnGetTimeout(((AosShellChannel*)instance)->iochannel->asyncchannel, time);
99
}
100

  
101
/**
102
 * @brief   Implementation of the BaseAsynchronous writet() method.
103
 */
104
static size_t _channelwritet(void *instance, const uint8_t *bp, size_t n, systime_t time)
105
{
106
  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_OUTPUT_ENABLED) {
107
    return chnWriteTimeout(((AosShellChannel*)instance)->iochannel->asyncchannel, bp, n, time);
108
  } else {
109
    return 0;
110
  }
111
}
112

  
113
/**
114
 * @brief   Implementation of the BaseAsynchronous readt() method.
115
 */
116
static size_t _channelreadt(void *instance, uint8_t *bp, size_t n, systime_t time)
117
{
118
  return chnReadTimeout(((AosShellChannel*)instance)->iochannel->asyncchannel, bp, n, time);
119
}
120

  
121
static const struct AosShellChannelVMT _channelvmt = {
122
  _channelwrite,
123
  _channelread,
124
  _channelput,
125
  _channelget,
126
  _channelputt,
127
  _channelgett,
128
  _channelwritet,
129
  _channelreadt,
130
};
131

  
132
static size_t _streamwrite(void *instance, const uint8_t *bp, size_t n)
133
{
134
  aosDbgCheck(instance != NULL);
135

  
136
  // local variables
137
  AosShellChannel* channel = ((AosShellStream*)instance)->channel;
138
  size_t bytes;
139
  size_t maxbytes = 0;
140

  
141
  // iterate through the list of channels
142
  while (channel != NULL) {
143
    bytes = streamWrite(channel, bp, n);
144
    maxbytes = (bytes > maxbytes) ? bytes : maxbytes;
145
    channel = channel->next;
146
  }
147

  
148
  return maxbytes;
149
}
150

  
151
static size_t _stremread(void *instance, uint8_t *bp, size_t n)
152
{
153
  (void)instance;
154
  (void)bp;
155
  (void)n;
156

  
157
  return 0;
158
}
159

  
160
static msg_t _streamput(void *instance, uint8_t b)
161
{
162
  aosDbgCheck(instance != NULL);
163

  
164
  // local variables
165
  AosShellChannel* channel = ((AosShellStream*)instance)->channel;
166
  msg_t ret;
167

  
168
  // iterate through the list of channels
169
  while (channel != NULL) {
170
    ret = streamPut(channel, b);
171
    if (ret != MSG_OK) {
172
      return ret;
173
    }
174
    channel = channel->next;
175
  }
176

  
177
  return MSG_OK;
178
}
179

  
180
static msg_t _streamget(void *instance)
181
{
182
  (void)instance;
183

  
184
  return 0;
185
}
186

  
187
static const struct AosShellStreamVMT _streamvmt = {
188
  _streamwrite,
189
  _stremread,
190
  _streamput,
191
  _streamget,
192
};
193

  
28 194
/**
29 195
 * @brief   Enumerator of special keyboard keys.
30 196
 */
......
64 230
static void _printPrompt(aos_shell_t* shell)
65 231
{
66 232
  aosDbgCheck(shell != NULL);
67
  aosDbgCheck(shell->stream != NULL);
68 233

  
69 234
  // print the system uptime before prompt is configured
70 235
  if (shell->config & AOS_SHELL_CONFIG_PROMPT_UPTIME) {
......
72 237
    aos_timestamp_t uptime;
73 238
    aosSysGetUptime(&uptime);
74 239

  
75
    chprintf(shell->stream, "[%01u:%02u:%02u:%02u:%03u:%03u] ",
76
           (uint32_t)(uptime / MICROSECONDS_PER_DAY),
77
           (uint8_t)(uptime % MICROSECONDS_PER_DAY / MICROSECONDS_PER_HOUR),
78
           (uint8_t)(uptime % MICROSECONDS_PER_HOUR / MICROSECONDS_PER_MINUTE),
79
           (uint8_t)(uptime % MICROSECONDS_PER_MINUTE / MICROSECONDS_PER_SECOND),
80
           (uint16_t)(uptime % MICROSECONDS_PER_SECOND / MICROSECONDS_PER_MILLISECOND),
81
           (uint16_t)(uptime % MICROSECONDS_PER_MILLISECOND / MICROSECONDS_PER_MICROSECOND));
240
    chprintf((BaseSequentialStream*)&shell->stream, "[%01u:%02u:%02u:%02u:%03u:%03u] ",
241
             (uint32_t)(uptime / MICROSECONDS_PER_DAY),
242
             (uint8_t)(uptime % MICROSECONDS_PER_DAY / MICROSECONDS_PER_HOUR),
243
             (uint8_t)(uptime % MICROSECONDS_PER_HOUR / MICROSECONDS_PER_MINUTE),
244
             (uint8_t)(uptime % MICROSECONDS_PER_MINUTE / MICROSECONDS_PER_SECOND),
245
             (uint16_t)(uptime % MICROSECONDS_PER_SECOND / MICROSECONDS_PER_MILLISECOND),
246
             (uint16_t)(uptime % MICROSECONDS_PER_MILLISECOND / MICROSECONDS_PER_MICROSECOND));
82 247
  }
83 248

  
84 249
  // print the actual prompt string
85 250
  if (shell->prompt && !(shell->config & AOS_SHELL_CONFIG_PROMPT_MINIMAL)) {
86
    chprintf(shell->stream, "%s$ ", shell->prompt);
251
    chprintf((BaseSequentialStream*)&shell->stream, "%s$ ", shell->prompt);
87 252
  } else {
88
    chprintf(shell->stream, "%>$ ");
253
    chprintf((BaseSequentialStream*)&shell->stream, "%>$ ");
89 254
  }
90 255

  
91 256
  return;
......
214 379
static int _moveCursor(aos_shell_t* shell, const size_t from, const size_t to)
215 380
{
216 381
  aosDbgCheck(shell != NULL);
217
  aosDbgCheck(shell->stream != NULL);
218 382

  
219 383
  // local variables
220 384
  size_t pos = from;
221 385

  
222 386
  // move cursor left by printing backspaces
223 387
  while (pos > to) {
224
    streamPut(shell->stream, '\b');
388
    streamPut(&shell->stream, '\b');
225 389
    --pos;
226 390
  }
227 391

  
228 392
  // move cursor right by printing line content
229 393
  while (pos < to) {
230
    streamPut(shell->stream, shell->line[pos]);
394
    streamPut(&shell->stream, shell->line[pos]);
231 395
    ++pos;
232 396
  }
233 397

  
......
246 410
static inline size_t _printLine(aos_shell_t* shell, const size_t from, const size_t to)
247 411
{
248 412
  aosDbgCheck(shell != NULL);
249
  aosDbgCheck(shell->stream != NULL);
250 413

  
251 414
  // local variables
252 415
  size_t cnt;
253 416

  
254 417
  for (cnt = 0; from + cnt < to; ++cnt) {
255
    streamPut(shell->stream, shell->line[from + cnt]);
418
    streamPut(&shell->stream, shell->line[from + cnt]);
256 419
  }
257 420

  
258 421
  return cnt;
......
363 526
  return _mapAscii2Custom(str1[i]) - _mapAscii2Custom(str2[i]);
364 527
}
365 528

  
366
/**
367
 * @brief   Reads a line from input stream
368
 * @details The line is directly written to the given shell object.
369
 *
370
 * @param[in] shell   Pointer to the shell object.
371
 *
372
 * @return              A status indicator.
373
 * @retval AOS_SUCCESS  Input sucessfully read, line is valid.
374
 * @retval AOS_ERROR    An I/O error occurred.
375
 */
376
static aos_status_t _readLine(aos_shell_t* shell)
529
static aos_status_t _readChannel(aos_shell_t* shell, AosShellChannel* channel, size_t* n)
377 530
{
378 531
  aosDbgCheck(shell != NULL);
379

  
380
  /*
381
   * Enumerator to encode a function.
382
   */
383
  typedef enum {
384
    READ_CHAR,
385
    AUTOFILL,
386
    SUGGEST,
387
    INS_TOGGLE,
388
    DELETE_FORWARD,
389
    DELETE_BACKWARD,
390
    RECALL_LAST,
391
    CLEAR,
392
    CURSOR2START,
393
    CURSOR2END,
394
    CURSOR_LEFT,
395
    CURSOR_RIGHT,
396
    EXECUTE,
397
    ESC_START,
398
    NONE,
399
  } func_t;
532
  aosDbgCheck(channel != NULL);
533
  aosDbgCheck(n != NULL);
400 534

  
401 535
  // local variables
402
  func_t func = NONE;
403
  func_t lastfunc = NONE;
404
  bool noinput = true;
405
  size_t lineend = 0;
406
  size_t cursorpos = 0;
536
  aos_shellaction_t action = AOS_SHELL_ACTION_NONE;
407 537
  char c;
408
  uint8_t escp = 0;
409
  char escseq[5] = {'\0'};
410 538

  
411
  // read character by character from stream
412
  while (streamRead(shell->stream, (uint8_t*)&c, 1)) {
539
  // initialize output variables
540
  *n = 0;
541

  
542
  // read character by character from the channel
543
  while (chnReadTimeout(channel, (uint8_t*)&c, 1, TIME_IMMEDIATE)) {
413 544
    special_key_t key = KEY_UNKNOWN;
414 545

  
415 546
    // parse escape sequence
416
    if (escp > 0) {
417
      escseq[escp] = c;
418
      ++escp;
419
      key = _interpreteEscapeSequence(escseq);
547
    if (shell->inputdata.escp > 0) {
548
      shell->inputdata.escseq[shell->inputdata.escp] = c;
549
      ++shell->inputdata.escp;
550
      key = _interpreteEscapeSequence(shell->inputdata.escseq);
420 551
      if (key == KEY_AMBIGUOUS) {
421 552
        // read next byte to resolve ambiguity
422 553
        continue;
423 554
      } else {
424
        // if the escape sequence could either be parsed sucessfully
425
        // or there is no match (KEY_UNKNOWN),
426
        // reset the sequence variables and interprete key/character
427
        escp = 0;
428
        memset(escseq, '\0', sizeof(escseq));
555
        /*
556
         * If the escape sequence could either be parsed sucessfully
557
         * or there is no match (KEY_UNKNOWN),
558
         * reset the sequence variable and interprete key/character
559
         */
560
        shell->inputdata.escp = 0;
561
        memset(shell->inputdata.escseq, '\0', sizeof(shell->inputdata.escseq)*sizeof(shell->inputdata.escseq[0]));
429 562
      }
430 563
    }
431 564

  
432
    // interprete keys or characters
565
    /* interprete keys or character */
433 566
    {
434
      func = NONE; // default
435
      if (key == KEY_UNKNOWN &&
436
          (/* printable character */ c >= '\x20' && c <= '\x7E') ) {
437
        func = READ_CHAR;
438
      } else if (key == KEY_TAB ||
439
                 /* horizontal tab ('\t') */ c == '\x09') {
440
        // pressing tab once applies auto fill,
441
        // presing a second time prints suggestions
442
        if (lastfunc == AUTOFILL || lastfunc == SUGGEST) {
443
          func = SUGGEST;
567
      // default
568
      action = AOS_SHELL_ACTION_NONE;
569

  
570
      // printable character
571
      if (key == KEY_UNKNOWN && c >= '\x20' && c <= '\x7E') {
572
        action = AOS_SHELL_ACTION_READCHAR;
573
      }
574

  
575
      // tab key or character
576
      else if (key == KEY_TAB || c == '\x09') {
577
        /*
578
         * pressing tab once applies auto fill
579
         * pressing tab a second time prints suggestions
580
         */
581
        if (shell->inputdata.lastaction == AOS_SHELL_ACTION_AUTOFILL || shell->inputdata.lastaction == AOS_SHELL_ACTION_SUGGEST) {
582
          action = AOS_SHELL_ACTION_SUGGEST;
444 583
        } else {
445
          func = AUTOFILL;
584
          action = AOS_SHELL_ACTION_AUTOFILL;
446 585
        }
447
      } else if (key == KEY_INSERT) {
448
        func = INS_TOGGLE;
449
      } else if (key == KEY_DELETE ||
450
                 /* [DEL] */ c == '\x7F') {
451
        // ignore of cursor is very right
452
        if (cursorpos < lineend) {
453
          func = DELETE_FORWARD;
586
      }
587

  
588
      // INS key
589
      else if (key == KEY_INSERT) {
590
        action = AOS_SHELL_ACTION_INSERTTOGGLE;
591
      }
592

  
593
      // DEL key or character
594
      else if (key == KEY_DELETE || c == '\x7F') {
595
        // ignore if cursor is at very right
596
        if (shell->inputdata.cursorpos < shell->inputdata.lineend) {
597
          action = AOS_SHELL_ACTION_DELETEFORWARD;
454 598
        }
455
      } else if (key == KEY_BACKSPACE ||
456
                 /* backpace ('\b') */c == '\x08') {
457
        // ignore if cursor is very left
458
        if (cursorpos > 0) {
459
          func = DELETE_BACKWARD;
599
      }
600

  
601
      // backspace key or character
602
      else if (key == KEY_BACKSPACE || c == '\x08') {
603
        // ignore if cursor is at very left
604
        if (shell->inputdata.cursorpos > 0) {
605
          action = AOS_SHELL_ACTION_DELETEBACKWARD;
460 606
        }
461
      } else if (key == KEY_PAGE_UP ||
462
                 key == KEY_ARROW_UP) {
607
      }
608

  
609
      // 'page up' of 'arrow up' key
610
      else if (key == KEY_PAGE_UP || key == KEY_ARROW_UP) {
463 611
        // ignore if there was some input
464
        if (noinput) {
465
          func = RECALL_LAST;
612
        if (shell->inputdata.noinput) {
613
          action = AOS_SHELL_ACTION_RECALLLAST;
466 614
        }
467
      } else if (key == KEY_PAGE_DOWN ||
468
                 key == KEY_ARROW_DOWN ||
469
                 /* end of test */ c == '\x03' ||
470
                 /* end of transmission */ c == '\x04') {
615
      }
616

  
617
      // 'page down' key, 'arrow done' key, 'end of test' character or 'end of transmission' character
618
      else if (key == KEY_PAGE_DOWN || key == KEY_ARROW_DOWN || c == '\x03' || c == '\x03') {
471 619
        // ignore if line is empty
472
        if (lineend > 0) {
473
          func = CLEAR;
620
        if (shell->inputdata.lineend > 0) {
621
          action = AOS_SHELL_ACTION_CLEAR;
474 622
        }
475
      } else if (key == KEY_HOME) {
623
      }
624

  
625
      // 'home' key
626
      else if (key == KEY_HOME) {
476 627
        // ignore if cursor is very left
477
        if (cursorpos > 0) {
478
          func = CURSOR2START;
628
        if (shell->inputdata.cursorpos > 0) {
629
          action = AOS_SHELL_ACTION_CURSOR2START;
479 630
        }
480
      } else if (key == KEY_END) {
481
        // ignore if cursor is very right
482
        if (cursorpos < lineend) {
483
          func = CURSOR2END;
631
      }
632

  
633
      // 'end' key
634
      else if (key == KEY_END) {
635
        // ignore if cursos is very right
636
        if (shell->inputdata.cursorpos < shell->inputdata.lineend) {
637
          action = AOS_SHELL_ACTION_CURSOR2END;
484 638
        }
485
      } else if (key == KEY_ARROW_LEFT) {
639
      }
640

  
641
      // 'arrow left' key
642
      else if (key == KEY_ARROW_LEFT) {
486 643
        // ignore if cursor is very left
487
        if (cursorpos > 0) {
488
          func = CURSOR_LEFT;
644
        if (shell->inputdata.cursorpos > 0) {
645
          action = AOS_SHELL_ACTION_CURSORLEFT;
489 646
        }
490
      } else if (key == KEY_ARROW_RIGHT) {
491
        // ignore if cursor is very right
492
        if (cursorpos < lineend) {
493
          func = CURSOR_RIGHT;
647
      }
648

  
649
      // 'arrow right' key
650
      else if (key == KEY_ARROW_RIGHT) {
651
        // irgnore if cursor is very right
652
        if (shell->inputdata.cursorpos < shell->inputdata.lineend) {
653
          action = AOS_SHELL_ACTION_CURSORRIGHT;
494 654
        }
495
      } else if (/* carriage return ('\r') */c == '\x0D' ||
496
                 /* line feed ('\n') */ c == '\x0A') {
497
        func = EXECUTE;
498
      } else if (key == KEY_ESCAPE ||
499
                 /* [ESCAPE] */ c == '\x1B') {
500
        func = ESC_START;
655
      }
656

  
657
      // carriage return ('\r') or line feed ('\n') character
658
      else if (c == '\x0D' || c == '\x0A') {
659
        action = AOS_SHELL_ACTION_EXECUTE;
660
      }
661

  
662
      // ESC key or [ESCAPE] character
663
      else if (key == KEY_ESCAPE || c == '\x1B') {
664
        action = AOS_SHELL_ACTION_ESCSTART;
501 665
      }
502 666
    }
503 667

  
504 668
    /* handle function */
505
    switch (func) {
506
      case READ_CHAR:
669
    switch (action) {
670
      case AOS_SHELL_ACTION_READCHAR:
671
      {
507 672
        // line is full
508
        if (lineend + 1 >= shell->linesize) {
509
          _moveCursor(shell, cursorpos, lineend);
510
          chprintf(shell->stream, "\n\tmaximum line width reached\n");
673
        if (shell->inputdata.lineend + 1 >= shell->linesize) {
674
          _moveCursor(shell, shell->inputdata.cursorpos, shell->inputdata.lineend);
675
          chprintf((BaseSequentialStream*)&shell->stream, "\n\tmaximum line width reached\n");
511 676
          _printPrompt(shell);
512
          _printLine(shell, 0, lineend);
513
          _moveCursor(shell, lineend, cursorpos);
677
          _printLine(shell, 0, shell->inputdata.lineend);
678
          _moveCursor(shell, shell->inputdata.lineend, shell->inputdata.cursorpos);
514 679
        }
515 680
        // read character
516 681
        else {
517 682
          // clear old line content on first input
518
          if (noinput) {
683
          if (shell->inputdata.noinput) {
519 684
            memset(shell->line, '\0', shell->linesize);
520
            noinput = false;
685
            shell->inputdata.noinput = false;
521 686
          }
522 687
          // overwrite content
523 688
          if (shell->config & AOS_SHELL_CONFIG_INPUT_OVERWRITE) {
524
            shell->line[cursorpos] = c;
525
            ++cursorpos;
526
            lineend = (cursorpos > lineend) ? cursorpos : lineend;
527
            streamPut(shell->stream, c);
689
            shell->line[shell->inputdata.cursorpos] = c;
690
            ++shell->inputdata.cursorpos;
691
            shell->inputdata.lineend = (shell->inputdata.cursorpos > shell->inputdata.lineend) ? shell->inputdata.cursorpos : shell->inputdata.lineend;
692
            streamPut(&shell->stream, (uint8_t)c);
528 693
          }
529 694
          // insert character
530 695
          else {
531
            memmove(&(shell->line[cursorpos+1]), &(shell->line[cursorpos]), lineend - cursorpos);
532
            shell->line[cursorpos] = c;
533
            ++lineend;
534
            _printLine(shell, cursorpos, lineend);
535
            ++cursorpos;
536
            _moveCursor(shell, lineend, cursorpos);
696
            memmove(&(shell->line[shell->inputdata.cursorpos+1]), &(shell->line[shell->inputdata.cursorpos]), shell->inputdata.lineend - shell->inputdata.cursorpos);
697
            shell->line[shell->inputdata.cursorpos] = c;
698
            ++shell->inputdata.lineend;
699
            _printLine(shell, shell->inputdata.cursorpos, shell->inputdata.lineend);
700
            ++shell->inputdata.cursorpos;
701
            _moveCursor(shell, shell->inputdata.lineend, shell->inputdata.cursorpos);
537 702
          }
538 703
        }
539 704
        break;
705
      }
540 706

  
541
      case AUTOFILL:
707
      case AOS_SHELL_ACTION_AUTOFILL:
542 708
      {
543 709
        const char* fill = shell->line;
544
        size_t cmatch = cursorpos;
710
        size_t cmatch = shell->inputdata.cursorpos;
545 711
        charmatch_t matchlevel = CHAR_MATCH_NOT;
546 712
        size_t n;
547 713
        // iterate through command list
......
556 722
                              strlen(cmd->name) - n :
557 723
                              0;
558 724
          // if an exact match was found
559
          if (cmatch + cmp == cursorpos) {
560
            cmatch = cursorpos;
725
          if (cmatch + cmp == shell->inputdata.cursorpos) {
726
            cmatch = shell->inputdata.cursorpos;
561 727
            fill = cmd->name;
562 728
            // break the loop only if there are no case mismatches with the input
563
            n = cursorpos;
729
            n = shell->inputdata.cursorpos;
564 730
            _strccmp(fill, shell->line, false, &n, &mlvl);
565 731
            if (mlvl == CHAR_MATCH_CASE) {
566 732
              break;
567 733
            }
568 734
          }
569 735
          // if a not exact match was found
570
          else if (cmatch + cmp > cursorpos) {
736
          else if (cmatch + cmp > shell->inputdata.cursorpos) {
571 737
            // if this is the first one
572 738
            if (fill == shell->line) {
573 739
              cmatch += cmp;
......
585 751
        n = cmatch;
586 752
        _strccmp(shell->line, fill, shell->config & AOS_SHELL_CONFIG_MATCH_CASE, &n, &matchlevel);
587 753
        // print the auto fill if any
588
        if (cmatch > cursorpos || (cmatch == cursorpos && matchlevel == CHAR_MATCH_NCASE)) {
589
          noinput = false;
754
        if (cmatch > shell->inputdata.cursorpos || (cmatch == shell->inputdata.cursorpos && matchlevel == CHAR_MATCH_NCASE)) {
755
          shell->inputdata.noinput = false;
590 756
          // limit auto fill so it will not overflow the line width
591
          if (lineend + (cmatch - cursorpos) > shell->linesize) {
592
            cmatch = shell->linesize - lineend + cursorpos;
757
          if (shell->inputdata.lineend + (cmatch - shell->inputdata.cursorpos) > shell->linesize) {
758
            cmatch = shell->linesize - shell->inputdata.lineend + shell->inputdata.cursorpos;
593 759
          }
594 760
          // move trailing memory further in the line
595
          memmove(&(shell->line[cmatch]), &(shell->line[cursorpos]), lineend - cursorpos);
596
          lineend += cmatch - cursorpos;
761
          memmove(&(shell->line[cmatch]), &(shell->line[shell->inputdata.cursorpos]), shell->inputdata.lineend - shell->inputdata.cursorpos);
762
          shell->inputdata.lineend += cmatch - shell->inputdata.cursorpos;
597 763
          // if there was no incorrect case when matching
598 764
          if (matchlevel == CHAR_MATCH_CASE) {
599 765
            // insert fill command name to line
600
            memcpy(&(shell->line[cursorpos]), &(fill[cursorpos]), cmatch - cursorpos);
766
            memcpy(&(shell->line[shell->inputdata.cursorpos]), &(fill[shell->inputdata.cursorpos]), cmatch - shell->inputdata.cursorpos);
601 767
            // print the output
602
            _printLine(shell, cursorpos, lineend);
768
            _printLine(shell, shell->inputdata.cursorpos, shell->inputdata.lineend);
603 769
          } else {
604 770
            // overwrite line with fill command name
605 771
            memcpy(shell->line, fill, cmatch);
606 772
            // reprint the whole line
607
            _moveCursor(shell, cursorpos, 0);
608
            _printLine(shell, 0, lineend);
773
            _moveCursor(shell, shell->inputdata.cursorpos, 0);
774
            _printLine(shell, 0, shell->inputdata.lineend);
609 775
          }
610 776
          // move cursor to the end of the matching sequence
611
          cursorpos = cmatch;
612
          _moveCursor(shell, lineend, cursorpos);
777
          shell->inputdata.cursorpos = cmatch;
778
          _moveCursor(shell, shell->inputdata.lineend, shell->inputdata.cursorpos);
613 779
        }
614 780
        break;
615 781
      }
616 782

  
617
      case SUGGEST:
783
      case AOS_SHELL_ACTION_SUGGEST:
618 784
      {
619 785
        unsigned int matches = 0;
620 786
        // iterate through command list
621 787
        for (aos_shellcommand_t* cmd = shell->commands; cmd != NULL; cmd = cmd->next) {
622 788
          // compare line content with command, excpet if cursorpos=0
623
          size_t i = cursorpos;
624
          if (cursorpos > 0) {
789
          size_t i = shell->inputdata.cursorpos;
790
          if (shell->inputdata.cursorpos > 0) {
625 791
            _strccmp(shell->line, cmd->name, true, &i, NULL);
626 792
          }
627
          const int cmp = (i < cursorpos) ?
628
                            (i - cursorpos) :
793
          const int cmp = (i < shell->inputdata.cursorpos) ?
794
                            (i - shell->inputdata.cursorpos) :
629 795
                            (cmd->name[i] != '\0') ?
630 796
                              strlen(cmd->name) - i :
631 797
                              0;
......
633 799
          if (cmp > 0) {
634 800
            // if this is the first one
635 801
            if (matches == 0) {
636
              _moveCursor(shell, cursorpos, lineend);
637
              streamPut(shell->stream, '\n');
802
              _moveCursor(shell, shell->inputdata.cursorpos, shell->inputdata.lineend);
803
              streamPut(&shell->stream, '\n');
638 804
            }
639 805
            // print the command
640
            chprintf(shell->stream, "\t%s\n", cmd->name);
806
            chprintf((BaseSequentialStream*)&shell->stream, "\t%s\n", cmd->name);
641 807
            ++matches;
642 808
          }
643 809
        }
644 810
        // reprint the prompt and line if any matches have been found
645 811
        if (matches > 0) {
646 812
          _printPrompt(shell);
647
          _printLine(shell, 0, lineend);
648
          _moveCursor(shell, lineend, cursorpos);
649
          noinput = false;
813
          _printLine(shell, 0, shell->inputdata.lineend);
814
          _moveCursor(shell, shell->inputdata.lineend, shell->inputdata.cursorpos);
815
          shell->inputdata.noinput = false;
650 816
        }
651 817
        break;
652 818
      }
653 819

  
654
      case INS_TOGGLE:
820
      case AOS_SHELL_ACTION_INSERTTOGGLE:
821
      {
655 822
        if (shell->config & AOS_SHELL_CONFIG_INPUT_OVERWRITE) {
656 823
          shell->config &= ~AOS_SHELL_CONFIG_INPUT_OVERWRITE;
657 824
        } else {
658 825
          shell->config |= AOS_SHELL_CONFIG_INPUT_OVERWRITE;
659 826
        }
660 827
        break;
828
      }
661 829

  
662
      case DELETE_FORWARD:
663
        --lineend;
664
        memmove(&(shell->line[cursorpos]), &(shell->line[cursorpos+1]), lineend - cursorpos);
665
        _printLine(shell, cursorpos, lineend);
666
        streamPut(shell->stream, ' ');
667
        _moveCursor(shell, lineend + 1, cursorpos);
830
      case AOS_SHELL_ACTION_DELETEFORWARD:
831
      {
832
        --shell->inputdata.lineend;
833
        memmove(&(shell->line[shell->inputdata.cursorpos]), &(shell->line[shell->inputdata.cursorpos+1]), shell->inputdata.lineend - shell->inputdata.cursorpos);
834
        _printLine(shell, shell->inputdata.cursorpos, shell->inputdata.lineend);
835
        streamPut(&shell->stream, ' ');
836
        _moveCursor(shell, shell->inputdata.lineend + 1, shell->inputdata.cursorpos);
668 837
        break;
838
      }
669 839

  
670
      case DELETE_BACKWARD:
671
        --cursorpos;
672
        memmove(&(shell->line[cursorpos]), &(shell->line[cursorpos+1]), lineend - cursorpos);
673
        --lineend;
674
        shell->line[lineend] = '\0';
675
        _moveCursor(shell, cursorpos + 1, cursorpos);
676
        _printLine(shell, cursorpos, lineend);
677
        streamPut(shell->stream, ' ');
678
        _moveCursor(shell, lineend+1, cursorpos);
840
      case AOS_SHELL_ACTION_DELETEBACKWARD:
841
      {
842
        --shell->inputdata.cursorpos;
843
        memmove(&(shell->line[shell->inputdata.cursorpos]), &(shell->line[shell->inputdata.cursorpos+1]), shell->inputdata.lineend - shell->inputdata.cursorpos);
844
        --shell->inputdata.lineend;
845
        shell->line[shell->inputdata.lineend] = '\0';
846
        _moveCursor(shell, shell->inputdata.cursorpos + 1, shell->inputdata.cursorpos);
847
        _printLine(shell, shell->inputdata.cursorpos, shell->inputdata.lineend);
848
        streamPut(&shell->stream, ' ');
849
        _moveCursor(shell, shell->inputdata.lineend+1, shell->inputdata.cursorpos);
679 850
        break;
851
      }
680 852

  
681
      case RECALL_LAST:
853
      case AOS_SHELL_ACTION_RECALLLAST:
682 854
      {
683 855
        // replace any intermediate NUL bytes with spaces
684
        lineend = 0;
856
        shell->inputdata.lineend = 0;
685 857
        size_t nul_start = 0;
686 858
        size_t nul_end = 0;
687 859
        // search line for a NUL byte
......
693 865
              if (shell->line[nul_end] != '\0') {
694 866
                // an intermediate NUL sequence was found
695 867
                memset(&(shell->line[nul_start]), ' ', nul_end - nul_start);
696
                lineend = nul_end + 1;
868
                shell->inputdata.lineend = nul_end + 1;
697 869
                break;
698 870
              } else {
699 871
                ++nul_end;
......
701 873
            }
702 874
            nul_start = nul_end + 1;
703 875
          } else {
704
            ++lineend;
876
            ++shell->inputdata.lineend;
705 877
            ++nul_start;
706 878
          }
707 879
        }
708
        cursorpos = lineend;
880
        shell->inputdata.cursorpos = shell->inputdata.lineend;
709 881
        // print the line
710
        noinput = _printLine(shell, 0, lineend) == 0;
882
        shell->inputdata.noinput = _printLine(shell, 0, shell->inputdata.lineend) == 0;
711 883
        break;
712 884
      }
713 885

  
714
      case CLEAR:
886
      case AOS_SHELL_ACTION_CLEAR:
887
      {
715 888
        // clear output
716
        _moveCursor(shell, cursorpos, 0);
717
        for (cursorpos = 0; cursorpos < lineend; ++cursorpos) {
718
          streamPut(shell->stream, ' ');
889
        _moveCursor(shell, shell->inputdata.cursorpos, 0);
890
        for (shell->inputdata.cursorpos = 0; shell->inputdata.cursorpos < shell->inputdata.lineend; ++shell->inputdata.cursorpos) {
891
          streamPut(&shell->stream, ' ');
719 892
        }
720
        _moveCursor(shell, lineend, 0);
721
        cursorpos = 0;
722
        lineend = 0;
723
        noinput = true;
893
        _moveCursor(shell, shell->inputdata.lineend, 0);
894
        shell->inputdata.cursorpos = 0;
895
        shell->inputdata.lineend = 0;
896
        shell->inputdata.noinput = true;
724 897
        break;
898
      }
725 899

  
726
      case CURSOR2START:
727
        _moveCursor(shell, cursorpos, 0);
728
        cursorpos = 0;
900
      case AOS_SHELL_ACTION_CURSOR2START:
901
      {
902
        _moveCursor(shell, shell->inputdata.cursorpos, 0);
903
        shell->inputdata.cursorpos = 0;
729 904
        break;
905
      }
730 906

  
731
      case CURSOR2END:
732
        _moveCursor(shell, cursorpos, lineend);
733
        cursorpos = lineend;
907
      case AOS_SHELL_ACTION_CURSOR2END:
908
      {
909
        _moveCursor(shell, shell->inputdata.cursorpos, shell->inputdata.lineend);
910
        shell->inputdata.cursorpos = shell->inputdata.lineend;
734 911
        break;
912
      }
735 913

  
736
      case CURSOR_LEFT:
737
        _moveCursor(shell, cursorpos, cursorpos-1);
738
        --cursorpos;
914
      case AOS_SHELL_ACTION_CURSORLEFT:
915
      {
916
        _moveCursor(shell, shell->inputdata.cursorpos, shell->inputdata.cursorpos-1);
917
        --shell->inputdata.cursorpos;
739 918
        break;
919
      }
740 920

  
741
      case CURSOR_RIGHT:
742
        _moveCursor(shell, cursorpos, cursorpos+1);
743
        ++cursorpos;
921
      case AOS_SHELL_ACTION_CURSORRIGHT:
922
      {
923
        _moveCursor(shell, shell->inputdata.cursorpos, shell->inputdata.cursorpos+1);
924
        ++shell->inputdata.cursorpos;
744 925
        break;
926
      }
745 927

  
746
      case EXECUTE:
747
        streamPut(shell->stream, '\n');
748
        // return a warning if there was no input
749
        if (noinput) {
750
          return AOS_WARNING;
751
        } else {
928
      case AOS_SHELL_ACTION_EXECUTE:
929
      {
930
        streamPut(&shell->stream, '\n');
931
        // set the number of read bytes and return
932
        if (!shell->inputdata.noinput) {
933
          *n = shell->linesize - shell->inputdata.lineend;
752 934
          // fill the remainder of the line with NUL bytes
753
          memset(&(shell->line[lineend]), '\0', shell->linesize - lineend);
754
          return AOS_SUCCESS;
935
          memset(&(shell->line[shell->inputdata.lineend]), '\0', *n);
936
          // reset static variables
937
          shell->inputdata.noinput = true;
755 938
        }
939
        return AOS_SUCCESS;
756 940
        break;
941
      }
757 942

  
758
      case ESC_START:
759
        escseq[0] = c;
760
        ++escp;
943
      case AOS_SHELL_ACTION_ESCSTART:
944
      {
945
        shell->inputdata.escseq[0] = c;
946
        ++shell->inputdata.escp;
761 947
        break;
948
      }
762 949

  
763
      case NONE:
950
      case AOS_SHELL_ACTION_NONE:
764 951
      default:
952
      {
765 953
        // do nothing (ignore input) and read next byte
766 954
        continue;
767 955
        break;
768
    }
956
      }
957
    } /* end of switch */
769 958

  
770
    lastfunc = func;
959
    shell->inputdata.lastaction = action;
771 960
  } /* end of while */
772 961

  
773
  /* This code is only executed when some error occurred.
774
   * The reason may be:
775
   *   - The input stream was disabled (streamRead() returned 0)
776
   *   - Parsing of input failed unexpectedly
777
   */
778
  return AOS_ERROR;
962
  // no more data could be read from the channel
963
  return AOS_WARNING;
779 964
}
780 965

  
781 966
/**
......
854 1039
 * @param[in] arglist       Pointer to the argument buffer.
855 1040
 * @param[in] arglistsize   Size of te argument buffer.
856 1041
 */
857
void aosShellInit(aos_shell_t* shell, BaseSequentialStream* stream, const char* prompt, char* line, size_t linesize, char** arglist, size_t arglistsize)
1042
void aosShellInit(aos_shell_t* shell, event_source_t* oseventsource,  const char* prompt, char* line, size_t linesize, char** arglist, size_t arglistsize)
858 1043
{
859 1044
  aosDbgCheck(shell != NULL);
860
  aosDbgCheck(stream != NULL);
1045
  aosDbgCheck(oseventsource != NULL);
861 1046
  aosDbgCheck(line != NULL);
862 1047
  aosDbgCheck(arglist != NULL);
863 1048

  
864 1049
  // set parameters
865 1050
  shell->thread = NULL;
866 1051
  chEvtObjectInit(&shell->eventSource);
867
  shell->stream = stream;
1052
  shell->os.eventSource = oseventsource;
1053
  aosShellStreamInit(&shell->stream);
868 1054
  shell->prompt = prompt;
869 1055
  shell->commands = NULL;
870 1056
  shell->execstatus.command = NULL;
871 1057
  shell->execstatus.retval = 0;
872 1058
  shell->line = line;
873 1059
  shell->linesize = linesize;
1060
  shell->inputdata.lastaction = AOS_SHELL_ACTION_NONE;
1061
  shell->inputdata.escp = 0;
1062
  memset(shell->inputdata.escseq, '\0', sizeof(shell->inputdata.escseq)*sizeof(shell->inputdata.escseq[0]));
1063
  shell->inputdata.cursorpos = 0;
1064
  shell->inputdata.lineend = 0;
1065
  shell->inputdata.noinput = true;
874 1066
  shell->arglist = arglist;
875 1067
  shell->arglistsize = arglistsize;
876 1068
  shell->config = 0x00;
......
885 1077
}
886 1078

  
887 1079
/**
1080
 * @brief   Initialize an AosShellStream object.
1081
 *
1082
 * @param[in] stream  The AosShellStrem to initialize.
1083
 */
1084
void aosShellStreamInit(AosShellStream* stream)
1085
{
1086
  aosDbgCheck(stream != NULL);
1087

  
1088
  stream->vmt = &_streamvmt;
1089
  stream->channel = NULL;
1090

  
1091
  return;
1092
}
1093

  
1094
/**
1095
 * @brief   Initialize an AosShellChannel object with the specified parameters.
1096
 *
1097
 * @param[in] channel     The AosShellChannel to initialize.
1098
 * @param[in] iochannel   An AosIOChannel this AosShellChannel is associated with.
1099
 */
1100
void aosShellChannelInit(AosShellChannel* channel, AosIOChannel* iochannel)
1101
{
1102
  aosDbgCheck(channel != NULL);
1103
  aosDbgCheck(iochannel != NULL && iochannel->asyncchannel != NULL);
1104

  
1105
  channel->vmt = &_channelvmt;
1106
  channel->iochannel = iochannel;
1107
  channel->next = NULL;
1108
  channel->flags = 0;
1109

  
1110
  return;
1111
}
1112

  
1113
/**
888 1114
 * @brief   Inserts a command to the shells list of commands.
889 1115
 *
890 1116
 * @param[in] shell   Pointer to the shell object.
......
906 1132
  aos_shellcommand_t** curr = &(shell->commands);
907 1133

  
908 1134
  // insert the command to the list wrt lexographical order (exception: lower case characters preceed upper their uppercase counterparts)
909
  while (1) {
910
    // if the end of the list was reached, append the command
911
    if (*curr == NULL) {
912
      *curr = cmd;
913
      return AOS_SUCCESS;
914
    } else {
915
      // iterate through the list as long as the command names are 'smaller'
916
      const int cmp = _strccmp((*curr)->name, cmd->name, true, NULL, NULL);
917
      if (cmp < 0) {
918
        prev = *curr;
919
        curr = &((*curr)->next);
920
        continue;
921
      }
922
      // error if the command already exists
923
      else if (cmp == 0) {
924
        return AOS_ERROR;
925
      }
926
      // insert the command as soon as a 'larger' name was found
927
      else /* if (cmpval > 0) */ {
928
        cmd->next = *curr;
929
        // special case: the first command is larger
930
        if (prev == NULL) {
931
          shell->commands = cmd;
932
        } else {
933
          prev->next = cmd;
934
        }
935
        return AOS_SUCCESS;
1135
  while (*curr != NULL) {
1136
    // iterate through the list as long as the command names are 'smaller'
1137
    const int cmp = _strccmp((*curr)->name, cmd->name, true, NULL, NULL);
1138
    if (cmp < 0) {
1139
      prev = *curr;
1140
      curr = &((*curr)->next);
1141
      continue;
1142
    }
1143
    // error if the command already exists
1144
    else if (cmp == 0) {
1145
      return AOS_ERROR;
1146
    }
1147
    // insert the command as soon as a 'larger' name was found
1148
    else /* if (cmpval > 0) */ {
1149
      cmd->next = *curr;
1150
      // special case: the first command is larger
1151
      if (prev == NULL) {
1152
        shell->commands = cmd;
1153
      } else {
1154
        prev->next = cmd;
936 1155
      }
1156
      return AOS_SUCCESS;
937 1157
    }
938 1158
  }
1159
  // the end of the list has been reached
1160

  
1161
  // append the command
1162
  *curr = cmd;
1163
  return AOS_SUCCESS;
939 1164
}
940 1165

  
941 1166
/**
......
992 1217
}
993 1218

  
994 1219
/**
1220
 * @brief   Add a channel to a AosShellStream.
1221
 *
1222
 * @param[in] stream    The AosShellStream to extend.
1223
 * @param[in] channel   The channel to be added to the stream.
1224
 */
1225
void aosShellStreamAddChannel(AosShellStream* stream, AosShellChannel* channel)
1226
{
1227
  aosDbgCheck(stream != NULL);
1228
  aosDbgCheck(channel != NULL && channel->iochannel != NULL && channel->iochannel->asyncchannel != NULL && channel->next == NULL && (channel->flags & AOS_SHELLCHANNEL_ATTACHED) == 0);
1229

  
1230
  // prepend the new channel
1231
  chSysLock();
1232
  channel->flags |= AOS_SHELLCHANNEL_ATTACHED;
1233
  channel->next = stream->channel;
1234
  stream->channel = channel;
1235
  chSysUnlock();
1236

  
1237
  return;
1238
}
1239

  
1240
/**
1241
 * @brief   Remove a channel from an AosShellStream.
1242
 *
1243
 * @param[in] stream    The AosShellStream to modify.
1244
 * @param[in] channel   The channel to remove.
1245
 * @return
1246
 */
1247
aos_status_t aosShellStreamRemoveChannel(AosShellStream* stream, AosShellChannel* channel)
1248
{
1249
  aosDbgCheck(stream != NULL);
1250
  aosDbgCheck(channel != NULL && channel->iochannel != NULL && channel->iochannel->asyncchannel != NULL && channel->flags & AOS_SHELLCHANNEL_ATTACHED);
1251

  
1252
  // local varibales
1253
  AosShellChannel* prev = NULL;
1254
  AosShellChannel* curr = stream->channel;
1255

  
1256
  // iterate through the list and search for the specified channel
1257
  while (curr != NULL) {
1258
    // if the channel was found
1259
    if (curr == channel) {
1260
      chSysLock();
1261
      // special case: the first channel matches (prev is NULL)
1262
      if (prev == NULL) {
1263
        stream->channel = curr->next;
1264
      } else {
1265
        prev->next = channel->next;
1266
      }
1267
      curr->next = NULL;
1268
      curr->flags &= ~AOS_SHELLCHANNEL_ATTACHED;
1269
      chSysUnlock();
1270
      return AOS_SUCCESS;
1271
    }
1272
  }
1273

  
1274
  // if the channel was not found, return an error
1275
  return AOS_ERROR;
1276
}
1277

  
1278
/**
1279
 * @brief   Enable a AosSheööChannel as input.
1280
 *
1281
 * @param[in] channel   The channel to enable as input.
1282
 */
1283
void aosShellChannelInputEnable(AosShellChannel* channel)
1284
{
1285
  aosDbgCheck(channel != NULL && channel->iochannel != NULL && channel->iochannel->asyncchannel != NULL);
1286

  
1287
  chSysLock();
1288
  channel->listener.wflags |= CHN_INPUT_AVAILABLE;
1289
  channel->flags |= AOS_SHELLCHANNEL_INPUT_ENABLED;
1290
  chSysUnlock();
1291

  
1292
  return;
1293
}
1294

  
1295
/**
1296
 * @brief   Disable a AosSheööChannel as input.
1297
 *
1298
 * @param[in] channel   The channel to disable as input.
1299
 */
1300
void aosShellChannelInputDisable( AosShellChannel* channel)
1301
{
1302
  aosDbgCheck(channel != NULL && channel->iochannel != NULL && channel->iochannel->asyncchannel != NULL);
1303

  
1304
  chSysLock();
1305
  channel->listener.wflags &= ~CHN_INPUT_AVAILABLE;
1306
  channel->flags &= ~AOS_SHELLCHANNEL_INPUT_ENABLED;
1307
  chSysUnlock();
1308

  
1309
  return;
1310
}
1311

  
1312
/**
1313
 * @brief   Enable a AosSheööChannel as output.
1314
 *
1315
 * @param[in] channel   The channel to enable as output.
1316
 */
1317
void aosShellChannelOutputEnable(AosShellChannel* channel)
1318
{
1319
  aosDbgCheck(channel != NULL && channel->iochannel != NULL && channel->iochannel->asyncchannel != NULL);
1320

  
1321
  channel->flags |= AOS_SHELLCHANNEL_OUTPUT_ENABLED;
1322

  
1323
  return;
1324
}
1325

  
1326
/**
1327
 * @brief   Disable a AosSheööChannel as output.
1328
 *
1329
 * @param[in] channel   The channel to disable as output.
1330
 */
1331
void aosShellChannelOutputDisable(AosShellChannel* channel)
1332
{
1333
  aosDbgCheck(channel != NULL && channel->iochannel != NULL && channel->iochannel->asyncchannel != NULL);
1334

  
1335
  channel->flags &= ~AOS_SHELLCHANNEL_OUTPUT_ENABLED;
1336

  
1337
  return;
1338
}
1339

  
1340
/**
995 1341
 * @brief   Thread main function.
996 1342
 *
997 1343
 * @param[in] aosShellThread    Name of the function;
......
1002 1348
  aosDbgCheck(shell != NULL);
1003 1349

  
1004 1350
  // local variables
1351
  eventmask_t eventmask;
1352
  eventflags_t eventflags;
1353
  AosShellChannel* channel;
1354
  aos_status_t readeval;
1355
  size_t nchars = 0;
1005 1356
  size_t nargs = 0;
1006
  aos_status_t readlval;
1357
  aos_shellcommand_t* cmd;
1358

  
1359

  
1360
  // register OS related events
1361
  chEvtRegisterMask(((aos_shell_t*)shell)->os.eventSource, &(((aos_shell_t*)shell)->os.eventListener), AOS_SHELL_EVENTMASK_OS);
1362
  // register events to all input channels
1363
  for (channel = ((aos_shell_t*)shell)->stream.channel; channel != NULL; channel = channel->next) {
1364
    chEvtRegisterMaskWithFlags(&(channel->iochannel->asyncchannel->event), &(channel->listener), AOS_SHELL_EVENTMASK_INPUT, channel->listener.wflags);
1365
  }
1007 1366

  
1008 1367
  // fire start event
1009 1368
  chEvtBroadcastFlags(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_START);
1010 1369

  
1370
  // print the prompt for the first time
1371
  _printPrompt((aos_shell_t*)shell);
1372

  
1011 1373
  // enter thread loop
1012 1374
  while (!chThdShouldTerminateX()) {
1013
    // print the prompt
1014
    _printPrompt((aos_shell_t*)shell);
1015

  
1016
    // read input line
1017
    readlval = _readLine((aos_shell_t*)shell);
1018
    if (readlval == AOS_ERROR) {
1019
      // emit an error event
1020
      chEvtBroadcastFlags(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_IOERROR);
1021
      // erither break the loop or try again afte some time
1022
      if (chThdShouldTerminateX()) {
1375
    // wait for event and handle it accordingly
1376
    eventmask = chEvtWaitOne(ALL_EVENTS);
1377

  
1378
    // handle event
1379
    switch (eventmask) {
1380

  
1381
      // OS related events
1382
      case AOS_SHELL_EVENTMASK_OS:
1383
      {
1384
        eventflags = chEvtGetAndClearFlags(&((aos_shell_t*)shell)->os.eventListener);
1385
        // handle shutdown/restart events
1386
        if (eventflags & AOS_SYSTEM_EVENTFLAGS_SHUTDOWN) {
1387
          chThdTerminate(((aos_shell_t*)shell)->thread);
1388
        } else {
1389
          // print an error message
1390
          chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "\nERROR: unknown OS event received (0x%08X)\n", eventflags);
1391
        }
1023 1392
        break;
1024
      } else {
1025
        aosThdSSleep(1);
1026 1393
      }
1027
    }
1028 1394

  
1029
    // parse input line to arguments only if reading the line was successful
1030
    nargs = (readlval == AOS_SUCCESS) ? _parseArguments((aos_shell_t*)shell) : 0;
1031
    if (nargs > ((aos_shell_t*)shell)->arglistsize) {
1032
      // error: too many arguments
1033
      chprintf(((aos_shell_t*)shell)->stream, "\tERROR: too many arguments\n");
1034
      continue;
1035
    }
1395
      // input events
1396
      case AOS_SHELL_EVENTMASK_INPUT:
1397
      {
1398
        // check and handle all channels
1399
        channel = ((aos_shell_t*)shell)->stream.channel;
1400
        while (channel != NULL) {
1401
          eventflags = chEvtGetAndClearFlags(&channel->listener);
1402
          // if there is new input
1403
          if (eventflags & CHN_INPUT_AVAILABLE) {
1404
            // if the channel is configured as input
1405
            if (channel->flags & AOS_SHELLCHANNEL_INPUT_ENABLED) {
1406
              // read input from channel
1407
              readeval = _readChannel((aos_shell_t*)shell, channel, &nchars);
1408
              // parse input line to argument list only if the input shall be executed
1409
              nargs = (readeval == AOS_SUCCESS && nchars > 0) ? _parseArguments((aos_shell_t*)shell) : 0;
1410
              // check number of arguments
1411
              if (nargs > ((aos_shell_t*)shell)->arglistsize) {
1412
                // error too many arguments
1413
                chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "\ttoo many arguments\n");
1414
              } else if (nargs > 0) {
1415
                // search command list for arg[0] and execute callback
1416
                cmd = ((aos_shell_t*)shell)->commands;
1417
                while (cmd != NULL) {
1418
                  if (strcmp(((aos_shell_t*)shell)->arglist[0], cmd->name) == 0) {
1419
                    ((aos_shell_t*)shell)->execstatus.command = cmd;
1420
                    chEvtBroadcastFlags(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_EXEC);
1421
                    ((aos_shell_t*)shell)->execstatus.retval = cmd->callback((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, nargs, ((aos_shell_t*)shell)->arglist);
1422
                    chEvtBroadcastFlags(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_DONE);
1423
                    // notify if the command was not successful
1424
                    if (((aos_shell_t*)shell)->execstatus.retval != 0) {
1425
                      chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "command returned exit status %d\n", ((aos_shell_t*)shell)->execstatus.retval);
1426
                    }
1427
                    break;
1428
                  }
1429
                  cmd = cmd->next;
1430
                } /* end of while */
1431

  
1432
                // if no matching command was found, print an error
1433
                if (cmd == NULL) {
1434
                  chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "%s: command not found\n", ((aos_shell_t*)shell)->arglist[0]);
1435
                }
1436
              }
1036 1437

  
1037
    // skip if there are no arguments
1038
    if (nargs > 0) {
1039
      // search command list for arg[0] and execure callback function
1040
      aos_shellcommand_t* cmd = ((aos_shell_t*)shell)->commands;
1041
      while (cmd != NULL) {
1042
        if (strcmp(((aos_shell_t*)shell)->arglist[0], cmd->name) == 0) {
1043
          ((aos_shell_t*)shell)->execstatus.command = cmd;
1044
          chEvtBroadcastFlags(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_EXEC);
1045
          ((aos_shell_t*)shell)->execstatus.retval = cmd->callback(((aos_shell_t*)shell)->stream, nargs, ((aos_shell_t*)shell)->arglist);
1046
          chEvtBroadcastFlags(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_DONE);
1047
          // append a line break so the next print will start from the very left
1048
          // usually this should just add an empty line, which is visually appealing
1049
          chprintf(((aos_shell_t*)shell)->stream, "\n");
1050
          // notify if the command was not successful
1051
          if (((aos_shell_t*)shell)->execstatus.retval != 0) {
1052
            chprintf(((aos_shell_t*)shell)->stream, "command returned exit status %d\n", ((aos_shell_t*)shell)->execstatus.retval);
1438
              // rreset some internal variables and eprint a new prompt
1439
              if (readeval == AOS_SUCCESS && !chThdShouldTerminateX()) {
1440
                ((aos_shell_t*)shell)->inputdata.cursorpos = 0;
1441
                ((aos_shell_t*)shell)->inputdata.lineend = 0;
1442
                _printPrompt((aos_shell_t*)shell);
1443
              }
1444
            }
1445
            // if the channel is not configured as input
1446
            else {
1447
              // read but drop all data
1448
              uint8_t c;
1449
              while (chnReadTimeout(channel, &c, 1, TIME_IMMEDIATE)) {
1450
                continue;
1451
              }
1452
            }
1053 1453
          }
1054
          break;
1454

  
1455
          // iterate to next channel
1456
          channel = channel->next;
1055 1457
        }
1056
        cmd = cmd->next;
1458
        break;
1057 1459
      }
1058
      // if no matching command was found, print an error
1059
      if (cmd == NULL) {
1060
        chprintf(((aos_shell_t*)shell)->stream, "%s: command not found\n", ((aos_shell_t*)shell)->arglist[0]);
1460

  
1461
      // other events
1462
      default:
1463
      {
1464
        // print an error message
1465
        chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "\nERROR: unknown event received (0x%08X)\n", eventmask);
1466
        break;
1061 1467
      }
1062
    }
1063 1468

  
1064
  } /* end of while loop */
1469
    } /* end of switch */
1470

  
1471
  } /* end of while */
1065 1472

  
1066 1473
  // fire event and exit the thread
1067 1474
  chSysLock();
......
1069 1476
  chThdExitS(MSG_OK);
1070 1477
  // no chSysUnlock() required since the thread has been terminated an all waiting threads have been woken up
1071 1478
}
1479

  
1480
#endif /* AMIROOS_CFG_SHELL_ENABLE == true */

Also available in: Unified diff