수정 (2021. 05. 13)
값을 입력받아서 사용할 수 있게 코드를 만들었다.
cli_function.c 파일을 보면 쉽게 이해할 수 있다.
=======================================
수정 (2021. 05. 01)
스페이스로 CLI명령어를 구분하는 것과 명령어에 문자를 입력하여 받을 수 있는 코드를 추가하였다.
아직 데이터는 문자열로 받아 저장하는 수준이지만 입력한 값을 사용할 수 있는 형식으로 코드를 수정할 생각이다.
또한 TAB키를 사용하여 자동 완성하는 코드, 이전에 사용한 명령어를 키보드 위, 아래 키로 불러오는 기능도 추가할 생각이다.
=======================================
CLI는 Command Line Interface 를 의미한다.
리눅스에서 마우스를 사용하지 않고 터미널과 키보드를 사용하여 명령을 내리는 것을 생각하면 된다.
STM32에서 이러한 기능을 간단하게 만들어 봤다.
terminal_key.txt 파일은 PuTTY, SmarTTY 같은 터미널 프로그램에서 키보드를 눌렀을 때 UART를 통해 받는 값을 써놓은 파일이다.
UART 코드 생성 (0)
Circular printf 에서 사용한 설정이랑 동일하다.
LL드라이버를 사용한다.
또한 PRINTF 함수도 이전 글에서 사용한 코드 그대로 사용한다.
코드 - cli.c (1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
void CLI_INIT(CLI_BASE* cli){
cli->cursor_position = 0;
cli->insert_position = 0;
cli->delete_position = 0;
cli->buffer_length = 0;
cli->insert_length = 0;
cli->delete_length = 0;
cli->is_insert = CLI_NOINSERT;
cli->is_delete = CLI_NODELETE;
}
void TERMINAL_INIT(TERMINAL_BASE* term, char* init_message){
PRINTF("%s%s",CLEAR_SCREEN.command,CURSOR_HOME.command);
PRINTF("%s",INSERT_MODE.command);
term->insert_mode = TERM_INSERT_MODE;
CLI_INIT(&(term->cli));
if(init_message != NULL)
PRINTF("%s\r\n",init_message);
PRINTF("%s: ",terminal.NAME);
}
void CLI_BUFFER_CONTROL(CLI_BASE * cli){
}
void TERMINAL_CONTROL_CLI(TERMINAL_BASE* term, TERMINAL_KEY* key ){
uint8_t enter_pressed=0;
uint8_t exit_pressed=0;
uint8_t temp_position;
if(key->is_pressed == KEY_PRESSED){
key->is_pressed = KEY_NONE;
switch(key->length){
case 1:
if(key->buf[0] == KEY_ENTER.key[0] || key->buf[0] == KEY_ENTER.key[1] ){
PRINTF("%s",KEY_ENTER.command);
enter_pressed = 1;
exit_pressed = 1;
}
else if(key->buf[0] == KEY_BACK_SPACE.key[0]){
if(term->cli.cursor_position !=0){
PRINTF("%s",KEY_BACK_SPACE.command);
term->cli.cursor_position--;
temp_position = term->cli.cursor_position;
while(temp_position != term->cli.buffer_length){
term->cli.buf[temp_position] = term->cli.buf[temp_position + 1];
temp_position++;
}
term->cli.buffer_length--;
}
}
else if(key->buf[0] == KEY_CTRL_C.key[0]){
exit_pressed = 1;
}
else{
PRINTF("%c",key->buf[0]);
if(term->insert_mode == TERM_REPLACE_MODE && (term->cli.cursor_position<term->cli.buffer_length)){
term->cli.buf[term->cli.cursor_position] = key->buf[0];
term->cli.cursor_position++;
}
else{
if(term->insert_mode == TERM_INSERT_MODE && term->cli.cursor_position < term->cli.buffer_length){
temp_position = term->cli.buffer_length;
while(term->cli.cursor_position != temp_position){
term->cli.buf[temp_position] = term->cli.buf[temp_position - 1];
temp_position--;
}
}
term->cli.buf[term->cli.cursor_position] = key->buf[0];
term->cli.cursor_position++;
term->cli.buffer_length++;
}
}
break;
case 2:
break;
case 3:
if(strncmp(key->buf,KEY_LEFT.key,3) == 0){
if(term->cli.cursor_position != 0){
PRINTF("%s",KEY_LEFT.command);
term->cli.cursor_position--;
}
}
else if(strncmp(key->buf,KEY_RIGHT.key,3) == 0){
if(term->cli.cursor_position < term->cli.buffer_length){
PRINTF("%s",KEY_RIGHT.command);
term->cli.cursor_position++;
}
}
else if(strncmp(key->buf,KEY_UP.key,3) == 0){
//PRINTF("%s",KEY_UP.command);
}
else if(strncmp(key->buf,KEY_DOWN.key,3) == 0){
//PRINTF("%s",KEY_DOWN.command);
}
break;
case 4:
if(strncmp(key->buf, KEY_DELETE.key,4)==0){
if(term->cli.cursor_position < term->cli.buffer_length){
PRINTF("%s",KEY_DELETE.command);
temp_position = term->cli.cursor_position;
while(temp_position != term->cli.buffer_length){
term->cli.buf[temp_position] = term->cli.buf[temp_position + 1];
temp_position++;
}
term->cli.buffer_length--;
}
}
else if(strncmp(key->buf, KEY_INSERT.key,4)==0){
if(term->insert_mode == TERM_REPLACE_MODE){
PRINTF("%s",INSERT_MODE.command);
term->insert_mode = TERM_INSERT_MODE;
}
else{
PRINTF("%s",REPLACE_MODE.command);
term->insert_mode = TERM_REPLACE_MODE;
}
}
break;
case 5:
break;
}
key->length = 0;
}
if(exit_pressed == 1){
//CLI_CONTROL_FUNCTION
if(enter_pressed == 1){
term->cli.buf[term->cli.buffer_length]=0;
PRINTF("%d %d :%s",term->cli.cursor_position, term->cli.buffer_length,term->cli.buf);
}
CLI_INIT(&(term->cli));
PRINTF("%s%s > ",KEY_ENTER.command, term->NAME);
}
}
|
CLI_INIT 함수는 기본 변수들을 초기화하는 함수이다. 실제로 사용하지 않는 변수들도 초기화하는데 원래 생각했던 설계 방향이랑 다르게 코드를 만들어서 사용하지 않은 변수들이다. 나중을 위해 바꾸지 않았다.
TERMINAL_INIT 함수는 main 함수 내에서 터미널을 초기화하고 기본 설정을 초기화하는 초기화 함수이다.
TERMINAL_CONTROL_CLI 함수가 키보드에서 입력을 받아 CLI작동을 하는 함수이다.
코드 - main.c (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/* USER CODE BEGIN 2 */
TERMINAL_INIT(&terminal,"START APP");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1){
TERMINAL_CONTROL_CLI(&terminal,&terminal_key);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
|
TERMINAL_INIT으로 초기화하고 무한 루프내에서 TERMINAL_CONTROL_CLI 함수가 작동한다.
결과 - (3)
(사진에서 2번째줄 ':' 문자를 '>' 문자로 바꾼 파일로 수정했다.)
실제 작동하면 초기 메시지가 뜨고 입력을 할 수 있다.
아직은 문자를 입력하면 커서 위치, 문자열 길이만 출력하는 간단한 기능으로 만들었다.
-
실제 CLI를 위한 기능은 차근차근 만들 생각이며 터미널에서 문자를 받을 때 DMA를 사용한 방식으로 변경할 계획이다.
CLI 명령어를 만드는 코드도 만들어 적용할 생각이다.
여러 기능을 추가한 코드에 대한 글이다.
https://ddtxrx.tistory.com/entry/STM32-CLI-1
'임베디드 > STM32' 카테고리의 다른 글
[STM32] CLI - (1) (0) | 2021.05.15 |
---|---|
[STM32] Circular Buffer printf (0) | 2021.03.16 |
[STM32] STM32cubeMX linux (0) | 2021.02.23 |
[STM32] 간단한 ICM20948 쿼터니언 (0) | 2020.09.18 |
[STM32] LL 드라이버 - MS5611 (0) | 2020.08.28 |