3 This file is part of the AVR-Crypto-Lib.
4 Copyright (C) 2008 Daniel Otte (daniel.otte@rub.de)
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 * email: daniel.otte@rub.de
23 * license: GPLv3 or later
25 * components to help implementing simple command based interaction
33 #include <avr/pgmspace.h>
37 cli_rx_fpt cli_rx = NULL;
38 cli_tx_fpt cli_tx = NULL;
41 void cli_putstr(char* s){
48 void cli_putstr_P(PGM_P s){
53 c = pgm_read_byte(s++);
60 void cli_hexdump(void* data, uint16_t length){
61 char hex_tab[] = {'0', '1', '2', '3',
68 cli_tx(hex_tab[(*((uint8_t*)data))>>4]);
69 cli_tx(hex_tab[(*((uint8_t*)data))&0xf]);
70 data = (uint8_t*)data +1;
75 void cli_auto_help(uint16_t maxcmdlength, PGM_VOID_P cmdlist){
81 cli_putstr_P(PSTR("\r\n[auto help] available commands:\r\n"
82 " <command> - <params> - <address>\r\n"));
84 item.cmd_name = (void*)pgm_read_word(cmdlist+0);
85 item.cmd_param_str = (void*)pgm_read_word(cmdlist+2);
86 item.cmd_function = (void_fpt)pgm_read_word(cmdlist+4);
87 cmdlist = (uint8_t*)cmdlist+6;
88 if(item.cmd_name==NULL){
92 cli_putstr_P(item.cmd_name);
93 i=maxcmdlength-strlen_P(item.cmd_name);
96 cli_putstr_P(PSTR(" - "));
97 if(item.cmd_param_str==NULL){
98 cli_putstr_P(PSTR("none \t- 0x"));
100 if(item.cmd_param_str==(void*)1){
101 cli_putstr_P(PSTR("yes \t- 0x"));
103 cli_putstr_P(item.cmd_param_str);
104 cli_putstr_P(PSTR(" \t- 0x"));
107 cli_hexdump(&item.cmd_function, 2);
108 cli_putstr_P(PSTR("\r\n"));
113 uint16_t firstword_length(char* s){
120 void echo_ctrl(char* s){
121 if(s==NULL || *s=='\0'){
122 cli_putstr_P(PSTR("\r\necho is "));
123 cli_putstr_P(cli_echo?PSTR("on"):PSTR("off"));
124 cli_putstr_P(PSTR("\r\n"));
127 if(!strcmp_P(s, PSTR("true")) || !strcmp_P(s, PSTR("on")) || *s=='1'){
130 if(!strcmp_P(s, PSTR("false")) || !strcmp_P(s, PSTR("off")) || *s=='0'){
135 typedef void(*str_fpt)(char*);
137 #define CLI_BACKSPACE 8
138 #define CLI_TABULATOR 9
140 int8_t search_and_call(char* cmd, uint16_t maxcmdlength, PGM_VOID_P cmdlist){
141 PGM_VOID_P cmdlist_orig = cmdlist;
142 if(*cmd=='\0' || *cmd=='#')
144 if(!strcmp_P(cmd, PSTR("exit")))
146 if((!strcmp_P(cmd, PSTR("help"))) || (!strcmp_P(cmd, PSTR("?")))){
147 cli_auto_help(maxcmdlength, cmdlist);
150 uint16_t fwlength=firstword_length(cmd);
152 memcpy(fw, cmd, fwlength);
154 cmdlist_entry_t item;
156 item.cmd_name = (void*)pgm_read_word(cmdlist+0);
157 item.cmd_param_str = (void*)pgm_read_word(cmdlist+2);
158 item.cmd_function = (void_fpt)pgm_read_word(cmdlist+4);
159 cmdlist = (uint8_t*)cmdlist+6;
160 }while(item.cmd_name!=NULL && strcmp_P(fw, item.cmd_name));
161 if(item.cmd_name==NULL){
162 cli_auto_help(maxcmdlength, cmdlist_orig);
164 if(item.cmd_function==NULL)
166 switch((uint16_t)item.cmd_param_str){
171 if(cmd[fwlength]=='\0'){
172 ((str_fpt)item.cmd_function)(cmd+fwlength);
174 ((str_fpt)item.cmd_function)(cmd+fwlength+1);
178 cli_putstr_P(PSTR("\r\nparam parsing currently not implemented!\r\n"));
186 uint16_t max_cmd_length(PGM_VOID_P cmdlist){
190 str = (char*)pgm_read_word(cmdlist);
191 cmdlist = (uint8_t*)cmdlist + 6;
200 uint16_t stridentcnt_P(char* a, PGM_P b){
204 c = pgm_read_byte(b++);
205 if(*a != c || c=='\0')
212 uint8_t cli_completion(char* buffer, uint16_t maxcmdlength, PGM_VOID_P cmdlist){
214 char ref[maxcmdlength+1];
217 /* check if we are behind the first word */
219 if(!isalnum(buffer[i++]))
223 itemstr = (char*)pgm_read_word(cmdlist);
226 cmdlist = (uint8_t*)cmdlist +6;
227 if(!strncmp_P(buffer, itemstr, i)){
229 strcpy_P(ref, itemstr);
231 ref[stridentcnt_P(ref, itemstr)]='\0';
235 i = strcmp(buffer, ref);
241 void cli_option_listing(char* buffer, PGM_VOID_P cmdlist){
243 uint16_t len=strlen(buffer);
245 itemstr = (char*)pgm_read_word(cmdlist);
247 cli_putstr_P(PSTR("\r\n>"));
251 cmdlist = (uint8_t*)cmdlist +6;
252 if(!strncmp_P(buffer, itemstr, len)){
253 cli_putstr_P(PSTR("\r\n "));
254 cli_putstr_P(itemstr);
259 int8_t cmd_interface(PGM_VOID_P cmd_desc){
260 uint16_t cli_buffer_size;
261 uint16_t cli_buffer_index;
263 uint8_t completion_failed=0;
266 uint16_t maxcmdlength = max_cmd_length(cmd_desc);
267 cli_buffer = calloc(1,cli_buffer_size=maxcmdlength+2);
277 if((exit_code=search_and_call(cli_buffer, maxcmdlength, cmd_desc))<=0){
281 memset(cli_buffer, 0, cli_buffer_size);
283 cli_putstr_P(PSTR("\r\n>"));
288 if(cli_buffer_index==0)
291 cli_buffer[cli_buffer_index] = '\0';
292 if(cli_echo && cli_tx){
297 if(completion_failed || cli_buffer_index==0){
299 cli_option_listing(cli_buffer, cmd_desc);
301 uint16_t old_idx = cli_buffer_index;
303 ~cli_completion(cli_buffer, maxcmdlength, cmd_desc);
304 cli_buffer_index = strlen(cli_buffer);
305 if(cli_echo && cli_tx){
306 while(old_idx<cli_buffer_index){
307 cli_tx(cli_buffer[old_idx++]);
314 if(cli_echo && cli_tx){
317 if(cli_buffer_index+1==cli_buffer_size){
318 cli_buffer = realloc(cli_buffer, cli_buffer_size+=CLI_BUFFER_BS);
322 memset(cli_buffer+cli_buffer_index+1, 0, CLI_BUFFER_BS);
324 cli_buffer[cli_buffer_index++] = c;