Statistics
| Branch: | Tag: | Revision:

amiro-os / core / src / aos_shell.c @ 96621a83

History | View | Annotate | Download (72.944 KB)

1
/*
2
AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
3
Copyright (C) 2016..2020  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) || defined(__DOXYGEN__)
32

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

    
37
/**
38
 * @brief   The character the input buffer is initialized with.
39
 */
40
#define INBUF_INIT_CHAR                         '\x07'
41

    
42
/**
43
 * @brief   Event mask to be set on OS related events.
44
 */
45
#define EVENTMASK_OS                            EVENT_MASK(0)
46

    
47
/**
48
 * @brief   Event mask to be set on a input event.
49
 */
50
#define EVENTMASK_INPUT                         EVENT_MASK(1)
51

    
52
/**
53
 * @brief   String that defines the INSERT key as specified by VT100.
54
 */
55
#define KEYSTRING_INSERT                        "\x1B\x5B\x32\x7E"
56

    
57
/**
58
 * @brief   String that defines the DEL key as specified by VT100.
59
 */
60
#define KEYSTRING_DELETE                        "\x1B\x5B\x33\x7E"
61

    
62
/**
63
 * @brief   String that defines the HOME key as specified by VT100.
64
 */
65
#define KEYSTRING_HOME                          "\x1B\x5B\x48"
66

    
67
/**
68
 * @brief   String that defines the END key as specified by VT100.
69
 */
70
#define KEYSTRING_END                           "\x1B\x5B\x46"
71

    
72
/**
73
 * @brief   String that defines the PGUP key as specified by VT100.
74
 */
75
#define KEYSTRING_PAGEUP                        "\x1B\x5B\x35\x7E"
76

    
77
/**
78
 * @brief   String that defines the PGUP key as specified by VT100.
79
 */
80
#define KEYSTRING_PAGEDOWN                      "\x1B\x5B\x36\x7E"
81

    
82
/**
83
 * @brief   String that defines the 'arrow down' key as specified by VT100.
84
 */
85
#define KEYSTRING_ARROWUP                       "\x1B\x5B\x41"
86

    
87
/**
88
 * @brief   String that defines the 'arrow up' key as specified by VT100.
89
 */
90
#define KEYSTRING_ARROWDOWN                     "\x1B\x5B\x42"
91

    
92
/**
93
 * @brief   String that defines the 'arrow left' key as specified by VT100.
94
 */
95
#define KEYSTRING_ARROWLEFT                     "\x1B\x5B\x44"
96

    
97
/**
98
 * @brief   String that defines the 'arrow right' key as specified by VT100.
99
 */
100
#define KEYSTRING_ARROWRIGHT                    "\x1B\x5B\x43"
101

    
102
/**
103
 * @brief   String that defines the CRTL + 'arrow up' key combination as specified by VT100.
104
 */
105
#define KEYSTRING_CTRL_ARROWUP                  "\x1B\x5B\x31\x3B\x35\x41"
106

    
107
/**
108
 * @brief   String that defines the CRTL + 'arrow down' key combination as specified by VT100.
109
 */
110
#define KEYSTRING_CTRL_ARROWDOWN                "\x1B\x5B\x31\x3B\x35\x42"
111

    
112
/**
113
 * @brief   String that defines the CRTL + 'arrow left' key combination as specified by VT100.
114
 */
115
#define KEYSTRING_CTRL_ARROWLEFT                "\x1B\x5B\x31\x3B\x35\x44"
116

    
117
/**
118
 * @brief   String that defines the CRTL + 'arrow right' key combination as specified by VT100.
119
 */
120
#define KEYSTRING_CTRL_ARROWRIGHT               "\x1B\x5B\x31\x3B\x35\x43"
121

    
122
/******************************************************************************/
123
/* EXPORTED VARIABLES                                                         */
124
/******************************************************************************/
125

    
126
/******************************************************************************/
127
/* LOCAL TYPES                                                                */
128
/******************************************************************************/
129

    
130
/*
131
 * forward declarations
132
 */
133
static size_t _channelwrite(void *instance, const uint8_t *bp, size_t n);
134
static size_t _channelread(void *instance, uint8_t *bp, size_t n);
135
static msg_t _channelput(void *instance, uint8_t b);
136
static msg_t _channelget(void *instance);
137
static msg_t _channelputt(void *instance, uint8_t b, sysinterval_t time);
138
static msg_t _channelgett(void *instance, sysinterval_t time);
139
static size_t _channelwritet(void *instance, const uint8_t *bp, size_t n, sysinterval_t time);
140
static size_t _channelreadt(void *instance, uint8_t *bp, size_t n, sysinterval_t time);
141
static msg_t _channelctl(void *instance, unsigned int operation, void *arg);
142
static size_t _streamwrite(void *instance, const uint8_t *bp, size_t n);
143
static size_t _stremread(void *instance, uint8_t *bp, size_t n);
144
static msg_t _streamput(void *instance, uint8_t b);
145
static msg_t _streamget(void *instance);
146

    
147
static const struct AosShellChannelVMT _channelvmt = {
148
  (size_t) 0,
149
  _channelwrite,
150
  _channelread,
151
  _channelput,
152
  _channelget,
153
  _channelputt,
154
  _channelgett,
155
  _channelwritet,
156
  _channelreadt,
157
  _channelctl,
158
};
159

    
160
static const struct AosShellStreamVMT _streamvmt = {
161
  (size_t) 0,
162
  _streamwrite,
163
  _stremread,
164
  _streamput,
165
  _streamget,
166
};
167

    
168
/**
169
 * @brief   Enumerator of special keyboard keys.
170
 */
171
typedef enum special_key {
172
  KEY_UNKNOWN,          /**< any/unknow key */
173
  KEY_AMBIGUOUS,        /**< key is ambiguous */
174
  KEY_TAB,              /**< tabulator key */
175
  KEY_BACKSPACE,        /**< backspace key */
176
  KEY_INSERT,           /**< insert key */
177
  KEY_DELETE,           /**< delete key */
178
  KEY_ESCAPE,           /**< escape key */
179
  KEY_HOME,             /**< home key */
180
  KEY_END,              /**< end key */
181
  KEY_PAGEUP,           /**< page up key */
182
  KEY_PAGEDOWN,         /**< page down key */
183
  KEY_ARROWUP,          /**< arrow up key */
184
  KEY_ARROWDOWN,        /**< arrow down key */
185
  KEY_ARROWLEFT,        /**< arrow left key */
186
  KEY_ARROWRIGHT,       /**< arrow right key */
187
  KEY_CTRL_ARROWUP,     /**< CTRL + arrow up key */
188
  KEY_CTRL_ARROWDOWN,   /**< CTRL + arrow down key */
189
  KEY_CTRL_ARROWLEFT,   /**< CTRL + arrow left key */
190
  KEY_CTRL_ARROWRIGHT,  /**< CTRL + arrow right key */
191
  KEY_CTRL_C,           /**< CTRL + C key */
192
} special_key_t;
193

    
194
/**
195
 * @brief   Enumerator for case (in)sensitive character matching.
196
 */
197
typedef enum charmatch {
198
  CHAR_MATCH_NOT    = 0,  /**< Characters do not match at all. */
199
  CHAR_MATCH_NCASE  = 1,  /**< Characters would match case insensitive. */
200
  CHAR_MATCH_CASE   = 2,  /**< Characters do match with case. */
201
} charmatch_t;
202

    
203
/**
204
 * @brief   Enumerator to encode shell actions.
205
 */
206
typedef enum aos_shellaction {
207
  ACTION_NONE,                  /**< No action at all. */
208
  ACTION_READCHAR,              /**< Read a printable character. */
209
  ACTION_AUTOCOMPLETE,          /**< Automatically comlete input by using available command. */
210
  ACTION_SUGGEST,               /**< Suggest matching available commands. */
211
  ACTION_EXECUTE,               /**< Execute input. */
212
  ACTION_DELETEBACKWARD,        /**< Delete a single character backwards. */
213
  ACTION_DELETEFORWARD,         /**< Delete a single character forwards. */
214
  ACTION_CLEAR,                 /**< Clear the input. */
215
  ACTION_RECALLPREVIOUS,        /**< Recall the previous (older) entry in the history. */
216
  ACTION_RECALLNEXT,            /**< Recall the next (more recent) entry in the history. */
217
  ACTION_RECALLOLDEST,          /**< Recall the oldest entry in the history. */
218
  ACTION_RECALLCURRENT,         /**< Recall the current input. */
219
  ACTION_CURSORLEFT,            /**< Move cursor one character to the left. */
220
  ACTION_CURSORRIGHT,           /**< Move cursor one character to the right. */
221
  ACTION_CURSORWORDLEFT,        /**< Move cursor one word to the left. */
222
  ACTION_CURSORWORDRIGHT,       /**< Move cursor one word to the right. */
223
  ACTION_CURSOR2END,            /**< Move cursor to the very right. */
224
  ACTION_CURSOR2START,          /**< Move cursor to the very left. */
225
  ACTION_RESET,                 /**< Reset the current input. */
226
  ACTION_INSERTTOGGLE,          /**< Toggle insertion mode. */
227
  ACTION_ESCSTART,              /**< Start an escape sequence (special keys). */
228
  ACTION_PRINTUNKNOWNSEQUENCE,  /**< Print an unknown escape sequence. */
229
} action_t;
230

    
231
/**
232
 * @brief   Struct that holds most important runtime data for the shell.
233
 * @details The structure is to be used by the shell thread main function as some kind of structured stack, which can be easily passed to other functions.
234
 */
235
typedef struct runtimedata {
236
  /**
237
   * @brief   Data related to the current input.
238
   */
239
  struct {
240
    /**
241
     * @brief   Length of the input.
242
     */
243
    size_t length;
244

    
245
    /**
246
     * @brief   Current position of the cursor in the input line.
247
     */
248
    size_t cursorpos;
249

    
250
    /**
251
     * @brief   Buffer to store escape sequences, which describe special characters.
252
     */
253
    char escseq[AOS_SHELL_ESCSEQUENCE_LENGTH];
254
  } input;
255

    
256
  /**
257
   * @brief   Data related to the entry or history buffer.
258
   */
259
  struct {
260
    /**
261
     * @brief   Current entry to be filled and executed.
262
     */
263
    size_t current;
264

    
265
    /**
266
     * @brief   Selected entry in the 'history' as preview.
267
     * @details A value of 0 indicates, that the line is cleared as a preview.
268
     *          A value of 1 indicates, that the current entry is selected.
269
     *          A value of t>1 indicates, that the entry t-1 in the past is selected.
270
     *          The value must never be greater than the number of entries available, of course.
271
     */
272
    size_t selected;
273

    
274
    /**
275
     * @brief   Selected entry in the 'history' that has been edited by the user.
276
     *          A value of 0 indicates, that there was no modification by the user yet (i.e. charcters, deletions or autofill).
277
     *          A value of 1 indicates, that the current entry was edited.
278
     *          A value of t>1 indicated, that a history entry was recalled and then edited.
279
     */
280
    size_t edited;
281
  } buffer;
282

    
283
  /**
284
   * @brief   The last action executed by the shell.
285
   */
286
  action_t lastaction;
287
} runtimedata_t;
288

    
289
/******************************************************************************/
290
/* LOCAL VARIABLES                                                            */
291
/******************************************************************************/
292

    
293
/******************************************************************************/
294
/* LOCAL FUNCTIONS                                                            */
295
/******************************************************************************/
296

    
297
/**
298
 * @brief   Implementation of the BaseAsynchronous write() method (inherited from BaseSequentialStream).
299
 */
300
static size_t _channelwrite(void *instance, const uint8_t *bp, size_t n)
301
{
302
  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_OUTPUT_ENABLED) {
303
    return streamWrite(((AosShellChannel*)instance)->asyncchannel, bp, n);
304
  } else {
305
    return 0;
306
  }
307
}
308

    
309
/**
310
 * @brief   Implementation of the BaseAsynchronous read() method (inherited from BaseSequentialStream).
311
 */
312
static size_t _channelread(void *instance, uint8_t *bp, size_t n)
313
{
314
  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_INPUT_ENABLED) {
315
    return streamRead(((AosShellChannel*)instance)->asyncchannel, bp, n);
316
  } else {
317
    return 0;
318
  }
319
}
320

    
321
/**
322
 * @brief   Implementation of the BaseAsynchronous put() method (inherited from BaseSequentialStream).
323
 */
324
static msg_t _channelput(void *instance, uint8_t b)
325
{
326
  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_OUTPUT_ENABLED) {
327
    return streamPut(((AosShellChannel*)instance)->asyncchannel, b);
328
  } else {
329
    return MSG_RESET;
330
  }
331
}
332

    
333
/**
334
 * @brief   Implementation of the BaseAsynchronous get() method (inherited from BaseSequentialStream).
335
 */
336
static msg_t _channelget(void *instance)
337
{
338
  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_INPUT_ENABLED) {
339
    return streamGet(((AosShellChannel*)instance)->asyncchannel);
340
  } else {
341
    return MSG_RESET;
342
  }
343
}
344

    
345
/**
346
 * @brief   Implementation of the BaseAsynchronous putt() method.
347
 */
348