Statistics
| Branch: | Tag: | Revision:

amiro-os / core / src / aos_shell.c @ f3ac1c96

History | View | Annotate | Download (49.45 KB)

1
/*
2
AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
3
Copyright (C) 2016..2019  Thomas Schöpping et al.
4

5
This program is free software: you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation, either version 3 of the License, or
8
(at your option) any later version.
9

10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
GNU General Public License for more details.
14

15
You should have received a copy of the GNU General Public License
16
along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
*/
18

    
19
/**
20
 * @file    aos_shell.c
21
 * @brief   Shell code.
22
 * @details Shell code as well as shell related channels and streams.
23
 *
24
 * @addtogroup aos_shell
25
 * @{
26
 */
27

    
28
#include <aos_shell.h>
29

    
30
#if (AMIROOS_CFG_SHELL_ENABLE == true) || (AMIROOS_CFG_TESTS_ENABLE == true)
31
#include <aos_debug.h>
32
#include <aos_time.h>
33
#include <aos_system.h>
34
#include <string.h>
35
/******************************************************************************/
36
/* LOCAL DEFINITIONS                                                          */
37
/******************************************************************************/
38

    
39
/**
40
 * @brief   Event mask to be set on OS related events.
41
 */
42
#define AOS_SHELL_EVENTMASK_OS                  EVENT_MASK(0)
43

    
44
/**
45
 * @brief   Event mask to be set on a input event.
46
 */
47
#define AOS_SHELL_EVENTMASK_INPUT               EVENT_MASK(1)
48

    
49
/******************************************************************************/
50
/* EXPORTED VARIABLES                                                         */
51
/******************************************************************************/
52

    
53
/******************************************************************************/
54
/* LOCAL TYPES                                                                */
55
/******************************************************************************/
56

    
57
/*
58
 * forward declarations
59
 */
60
static size_t _channelwrite(void *instance, const uint8_t *bp, size_t n);
61
static size_t _channelread(void *instance, uint8_t *bp, size_t n);
62
static msg_t _channelput(void *instance, uint8_t b);
63
static msg_t _channelget(void *instance);
64
static msg_t _channelputt(void *instance, uint8_t b, sysinterval_t time);
65
static msg_t _channelgett(void *instance, sysinterval_t time);
66
static size_t _channelwritet(void *instance, const uint8_t *bp, size_t n, sysinterval_t time);
67
static size_t _channelreadt(void *instance, uint8_t *bp, size_t n, sysinterval_t time);
68
static msg_t _channelctl(void *instance, unsigned int operation, void *arg);
69
static size_t _streamwrite(void *instance, const uint8_t *bp, size_t n);
70
static size_t _stremread(void *instance, uint8_t *bp, size_t n);
71
static msg_t _streamput(void *instance, uint8_t b);
72
static msg_t _streamget(void *instance);
73

    
74
static const struct AosShellChannelVMT _channelvmt = {
75
  (size_t) 0,
76
  _channelwrite,
77
  _channelread,
78
  _channelput,
79
  _channelget,
80
  _channelputt,
81
  _channelgett,
82
  _channelwritet,
83
  _channelreadt,
84
  _channelctl,
85
};
86

    
87
static const struct AosShellStreamVMT _streamvmt = {
88
  (size_t) 0,
89
  _streamwrite,
90
  _stremread,
91
  _streamput,
92
  _streamget,
93
};
94

    
95
/**
96
 * @brief   Enumerator of special keyboard keys.
97
 */
98
typedef enum special_key {
99
  KEY_UNKNOWN,      /**< any/unknow key */
100
  KEY_AMBIGUOUS,    /**< key is ambiguous */
101
  KEY_TAB,          /**< tabulator key */
102
  KEY_ESCAPE,       /**< escape key */
103
  KEY_BACKSPACE,    /**< backspace key */
104
  KEY_INSERT,       /**< insert key */
105
  KEY_DELETE,       /**< delete key */
106
  KEY_HOME,         /**< home key */
107
  KEY_END,          /**< end key */
108
  KEY_PAGE_UP,      /**< page up key */
109
  KEY_PAGE_DOWN,    /**< page down key */
110
  KEY_ARROW_UP,     /**< arrow up key */
111
  KEY_ARROW_DOWN,   /**< arrow down key */
112
  KEY_ARROW_LEFT,   /**< arrow left key */
113
  KEY_ARROW_RIGHT,  /**< arrow right key */
114
} special_key_t;
115

    
116
/**
117
 * @brief   Enumerator for case (in)sensitive character matching.
118
 */
119
typedef enum charmatch {
120
  CHAR_MATCH_NOT    = 0,  /**< Characters do not match at all. */
121
  CHAR_MATCH_NCASE  = 1,  /**< Characters would match case insensitive. */
122
  CHAR_MATCH_CASE   = 2,  /**< Characters do match with case. */
123
} charmatch_t;
124

    
125
/******************************************************************************/
126
/* LOCAL VARIABLES                                                            */
127
/******************************************************************************/
128

    
129
/******************************************************************************/
130
/* LOCAL FUNCTIONS                                                            */
131
/******************************************************************************/
132

    
133
/**
134
 * @brief   Implementation of the BaseAsynchronous write() method (inherited from BaseSequentialStream).
135
 */
136
static size_t _channelwrite(void *instance, const uint8_t *bp, size_t n)
137
{
138
  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_OUTPUT_ENABLED) {
139
    return streamWrite(((AosShellChannel*)instance)->asyncchannel, bp, n);
140
  } else {
141
    return 0;
142
  }
143
}
144

    
145
/**
146
 * @brief   Implementation of the BaseAsynchronous read() method (inherited from BaseSequentialStream).
147
 */
148
static size_t _channelread(void *instance, uint8_t *bp, size_t n)
149
{
150
  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_INPUT_ENABLED) {
151
    return streamRead(((AosShellChannel*)instance)->asyncchannel, bp, n);
152
  } else {
153
    return 0;
154
  }
155
}
156

    
157
/**
158
 * @brief   Implementation of the BaseAsynchronous put() method (inherited from BaseSequentialStream).
159
 */
160
static msg_t _channelput(void *instance, uint8_t b)
161
{
162
  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_OUTPUT_ENABLED) {
163
    return streamPut(((AosShellChannel*)instance)->asyncchannel, b);
164
  } else {
165
    return MSG_RESET;
166
  }
167
}
168

    
169
/**
170
 * @brief   Implementation of the BaseAsynchronous get() method (inherited from BaseSequentialStream).
171
 */
172
static msg_t _channelget(void *instance)
173
{
174
  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_INPUT_ENABLED) {
175
    return streamGet(((AosShellChannel*)instance)->asyncchannel);
176
  } else {
177
    return MSG_RESET;
178
  }
179
}
180

    
181
/**
182
 * @brief   Implementation of the BaseAsynchronous putt() method.
183
 */
184
static msg_t _channelputt(void *instance, uint8_t b, sysinterval_t time)
185
{
186
  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_OUTPUT_ENABLED) {
187
    return chnPutTimeout(((AosShellChannel*)instance)->asyncchannel, b, time);
188
  } else {
189
    return MSG_RESET;
190
  }
191
}
192

    
193
/**
194
 * @brief   Implementation of the BaseAsynchronous gett() method.
195
 */
196
static msg_t _channelgett(void *instance, sysinterval_t time)
197
{
198
  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_INPUT_ENABLED) {
199
    return chnGetTimeout(((AosShellChannel*)instance)->asyncchannel, time);
200
  } else {
201
    return MSG_RESET;
202
  }
203
}
204

    
205
/**
206
 * @brief   Implementation of the BaseAsynchronous writet() method.
207
 */
208
static size_t _channelwritet(void *instance, const uint8_t *bp, size_t n, sysinterval_t time)
209
{
210
  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_OUTPUT_ENABLED) {
211
    return chnWriteTimeout(((AosShellChannel*)instance)->asyncchannel, bp, n, time);
212
  } else {
213
    return 0;
214
  }
215
}
216

    
217
/**
218
 * @brief   Implementation of the BaseAsynchronous readt() method.
219
 */
220
static size_t _channelreadt(void *instance, uint8_t *bp, size_t n, sysinterval_t time)
221
{
222
  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_INPUT_ENABLED) {
223
    return chnReadTimeout(((AosShellChannel*)instance)->asyncchannel, bp, n, time);
224
  } else {
225
    return 0;
226
  }
227
}
228

    
229
/**
230
 * @brief   Implementation of the BaseAsynchronousChannel ctl() method.
231
 */
232
static msg_t _channelctl(void *instance, unsigned int operation, void *arg)
233
{
234
  (void) instance;
235

    
236
  switch (operation) {
237
  case CHN_CTL_NOP:
238
    osalDbgCheck(arg == NULL);
239
    break;
240
  case CHN_CTL_INVALID:
241
    osalDbgAssert(false, "invalid CTL operation");
242
    break;
243
  default:
244
    break;
245
  }
246
  return MSG_OK;
247
}
248

    
249
static size_t _streamwrite(void *instance, const uint8_t *bp, size_t n)
250
{
251
  aosDbgCheck(instance != NULL);
252

    
253
  // local variables
254
  AosShellChannel* channel = ((AosShellStream*)instance)->channel;
255
  size_t bytes;
256
  size_t maxbytes = 0;
257

    
258
  // iterate through the list of channels
259
  while (channel != NULL) {
260
    bytes = streamWrite(channel, bp, n);
261
    maxbytes = (bytes > maxbytes) ? bytes : maxbytes;
262
    channel = channel->next;
263
  }
264

    
265
  return maxbytes;
266
}
267

    
268
static size_t _stremread(void *instance, uint8_t *bp, size_t n)
269
{
270
  (void)instance;
271
  (void)bp;
272
  (void)n;
273

    
274
  return 0;
275
}
276

    
277
static msg_t _streamput(void *instance, uint8_t b)
278
{
279
  aosDbgCheck(instance != NULL);
280

    
281
  // local variables
282
  AosShellChannel* channel = ((AosShellStream*)instance)->channel;
283
  msg_t ret = MSG_OK;
284

    
285
  // iterate through the list of channels
286
  while (channel != NULL) {
287
    msg_t ret_ = streamPut(channel, b);
288
    ret = (ret_ < ret) ? ret_ : ret;
289
    channel = channel->next;
290
  }
291

    
292
  return ret;
293
}
294

    
295
static msg_t _streamget(void *instance)
296
{
297
  (void)instance;
298

    
299
  return 0;
300
}
301

    
302
/**
303
 * @brief   Print the shell prompt
304
 * @details Depending on the configuration flags, the system uptime is printed before the prompt string.
305
 *
306
 * @param[in] shell   Pointer to the shell object.
307
 */
308
static void _printPrompt(aos_shell_t* shell)
309
{
310
  aosDbgCheck(shell != NULL);
311

    
312
  // print some time informattion before prompt if configured
313
  if (shell->config & (AOS_SHELL_CONFIG_PROMPT_UPTIME | AOS_SHELL_CONFIG_PROMPT_DATETIME)) {
314
    // printf the system uptime
315
    if ((shell->config & (AOS_SHELL_CONFIG_PROMPT_UPTIME | AOS_SHELL_CONFIG_PROMPT_DATETIME)) == AOS_SHELL_CONFIG_PROMPT_UPTIME) {
316
      // get current system uptime
317
      aos_timestamp_t uptime;
318
      aosSysGetUptime(&uptime);
319

    
320
      chprintf((BaseSequentialStream*)&shell->stream, "[%01u:%02u:%02u:%02u:%03u:%03u] ",
321
               (uint32_t)(uptime / MICROSECONDS_PER_DAY),
322
               (uint8_t)(uptime % MICROSECONDS_PER_DAY / MICROSECONDS_PER_HOUR),
323
               (uint8_t)(uptime % MICROSECONDS_PER_HOUR / MICROSECONDS_PER_MINUTE),
324
               (uint8_t)(uptime % MICROSECONDS_PER_MINUTE / MICROSECONDS_PER_SECOND),
325
               (uint16_t)(uptime % MICROSECONDS_PER_SECOND / MICROSECONDS_PER_MILLISECOND),
326
               (uint16_t)(uptime % MICROSECONDS_PER_MILLISECOND / MICROSECONDS_PER_MICROSECOND));
327
    }
328
    else if ((shell->config & (AOS_SHELL_CONFIG_PROMPT_UPTIME | AOS_SHELL_CONFIG_PROMPT_DATETIME)) == AOS_SHELL_CONFIG_PROMPT_DATETIME) {
329
      // get current RTC time
330
      struct tm dt;
331
      aosSysGetDateTime(&dt);
332
      chprintf((BaseSequentialStream*)&shell->stream, "[%02u-%02u-%04u|%02u:%02u:%02u] ",
333
               dt.tm_mday,
334
               dt.tm_mon + 1,
335
               dt.tm_year + 1900,
336
               dt.tm_hour,
337
               dt.tm_min,
338
               dt.tm_sec);
339
    }
340
    else {
341
      aosDbgAssert(false);
342
    }
343
  }
344

    
345
  // print the actual prompt string
346
  if (shell->prompt && !(shell->config & AOS_SHELL_CONFIG_PROMPT_MINIMAL)) {
347
    chprintf((BaseSequentialStream*)&shell->stream, "%s$ ", shell->prompt);
348
  } else {
349
    chprintf((BaseSequentialStream*)&shell->stream, "%>$ ");
350
  }
351

    
352
  return;
353
}
354

    
355
/**
356
 * @brief   Interprete a escape sequence
357
 *
358
 * @param[in] seq   Character sequence to interprete.
359
 *                  Must be terminated by NUL byte.
360
 *
361
 * @return          A @p special_key value.
362
 */
363
static special_key_t _interpreteEscapeSequence(const char seq[])
364
{
365
  // local variables
366
  bool ambiguous = false;
367