Statistics
| Branch: | Tag: | Revision:

amiro-os / core / src / aos_shell.c @ 437900eb

History | View | Annotate | Download (54.761 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 <amiroos.h>
29
#include <string.h>
30

    
31
#if (AMIROOS_CFG_SHELL_ENABLE == true) || (AMIROOS_CFG_TESTS_ENABLE == true)
32

    
33
/******************************************************************************/
34
/* LOCAL DEFINITIONS                                                          */
35
/******************************************************************************/
36

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

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

    
47
/******************************************************************************/
48
/* EXPORTED VARIABLES                                                         */
49
/******************************************************************************/
50

    
51
/******************************************************************************/
52
/* LOCAL TYPES                                                                */
53
/******************************************************************************/
54

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

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

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

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

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

    
127
/******************************************************************************/
128
/* LOCAL VARIABLES                                                            */
129
/******************************************************************************/
130

    
131
/******************************************************************************/
132
/* LOCAL FUNCTIONS                                                            */
133
/******************************************************************************/
134

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

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

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

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

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

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

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

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

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

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

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

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

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

    
267
  return maxbytes;
268
}
269

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

    
276
  return 0;
277
}
278

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

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

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

    
294
  return ret;
295
}
296

    
297
static msg_t _streamget(void *instance)
298
{
299
  (void)instance;
300

    
301
  return 0;
302
}
303

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

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

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

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

    
356
  return;
357
}
358

    
359
/**
360
 * @brief   Interprete a escape sequence
361
 * @details This function interpretes escape sequences (starting with ASCII
362
 *          "Escape" character 0x1B) according to the VT100 / VT52 ANSI escape
363
 *          sequence definitions.
364
 * @note    Only the most important escape sequences are implemented yet.
365
 *
366
 * @param[in] seq   Character sequence to interprete.
367
 *                  Must be terminated by NUL byte.