Statistics
| Branch: | Tag: | Revision:

amiro-os / core / src / aos_shell.c @ 7de0cc90

History | View | Annotate | Download (49.698 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
} special_key_t;
113

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

    
123
/******************************************************************************/
124
/* LOCAL VARIABLES                                                            */
125
/******************************************************************************/
126

    
127
/******************************************************************************/
128
/* LOCAL FUNCTIONS                                                            */
129
/******************************************************************************/
130

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

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

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

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

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

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

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

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

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

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

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

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

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

    
263
  return maxbytes;
264
}
265

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

    
272
  return 0;
273
}
274

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

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

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

    
290
  return ret;
291
}
292

    
293
static msg_t _streamget(void *instance)
294
{
295
  (void)instance;
296

    
297
  return 0;
298
}
299

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

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

    
318
      chprintf((BaseSequentialStream*)&shell->stream, "[%01u:%02u:%02u:%02u:%03u:%03u] ",
319
               (uint32_t)(uptime / MICROSECONDS_PER_DAY),
320
               (uint8_t)(uptime % MICROSECONDS_PER_DAY / MICROSECONDS_PER_HOUR),
321
               (uint8_t)(uptime % MICROSECONDS_PER_HOUR / MICROSECONDS_PER_MINUTE),
322
               (uint8_t)(uptime % MICROSECONDS_PER_MINUTE / MICROSECONDS_PER_SECOND),
323
               (uint16_t)(uptime % MICROSECONDS_PER_SECOND / MICROSECONDS_PER_MILLISECOND),
324
               (uint16_t)(uptime % MICROSECONDS_PER_MILLISECOND / MICROSECONDS_PER_MICROSECOND));
325
    }
326
#if (HAL_USE_RTC == TRUE)
327
    else if ((shell->config & (AOS_SHELL_CONFIG_PROMPT_UPTIME | AOS_SHELL_CONFIG_PROMPT_DATETIME)) == AOS_SHELL_CONFIG_PROMPT_DATETIME) {
328
      // get current RTC time
329
      struct tm dt;
330
      aosSysGetDateTime(&dt);
331
      chprintf((BaseSequentialStream*)&shell->stream, "[%02u-%02u-%04u|%02u:%02u:%02u] ",
332
               dt.tm_mday,
333
               dt.tm_mon + 1,
334
               dt.tm_year + 1900,
335
               dt.tm_hour,
336
               dt.tm_min,
337
               dt.tm_sec);
338
    }
339
#endif /* (HAL_USE_RTC == TRUE) */
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
 * @details This function interpretes escape sequences (starting with ASCII
358
 *          "Escape" character 0x1B) according to the VT100 / VT52 ANSI escape
359
 *          sequence definitions.
360
 * @note    Only the most important escape sequences are implemented yet.
361
 *
362
 * @param[in] seq   Character sequence to interprete.
363
 *                  Must be terminated by NUL byte.
364
 *
365
 * @return          A @p special_key value.
366
 */
367
static special_