Skip to content

Commit 65016f3

Browse files
committed
Object oriented way
This experiment aims to make this whole library object oriented. I hope that it will be easyer to use while the functionality expands further.
1 parent fe56738 commit 65016f3

File tree

6 files changed

+656
-795
lines changed

6 files changed

+656
-795
lines changed

src/commander.cpp

Lines changed: 388 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,388 @@
1+
/*
2+
* commander.cpp
3+
*
4+
* Created on: Feb 5, 2022
5+
* Author: dani0
6+
*/
7+
8+
#include "commander.hpp"
9+
10+
11+
void Commander::attachTreeFunction( API_t *API_tree_p, uint32_t API_tree_size_p ){
12+
13+
API_tree = API_tree_p;
14+
API_tree_size = API_tree_size_p;
15+
16+
}
17+
18+
void Commander::attachDebugPort( Serial *debugPort_p ){
19+
20+
debugPort = debugPort_p;
21+
22+
}
23+
24+
void Commander::init(){
25+
26+
uint32_t i;
27+
uint32_t j;
28+
29+
API_t temp;
30+
31+
if( debugPort ){
32+
33+
debugPort -> println( "Rendezes elott:" );
34+
for( i = 0; i < API_tree_size; i++ ){
35+
36+
debugPort -> printf( "%d. %s\r\n", i, API_tree[ i ].name );
37+
38+
}
39+
debugPort -> println();
40+
41+
}
42+
43+
// Nev szerint sorba rendezzuk a parancsokat.
44+
for( i = 0; i < API_tree_size; i++ ){
45+
46+
for( j = i + 1; j < API_tree_size; j++ ){
47+
48+
//if( API_tree[ i ] > API_tree[ j ] ){
49+
if( strcmp( API_tree[ i ].name, API_tree[ j ].name ) > 0 ){
50+
51+
temp = API_tree[ i ];
52+
API_tree[ i ] = API_tree[ j ];
53+
API_tree[ j ] = temp;
54+
55+
}
56+
57+
}
58+
59+
}
60+
61+
if( debugPort ){
62+
63+
debugPort -> println( "Rendezes utan:" );
64+
for( i = 0; i < API_tree_size; i++ ){
65+
66+
debugPort -> printf( "%d. %s\r\n", i, API_tree[ i ].name );
67+
68+
}
69+
debugPort -> println();
70+
71+
}
72+
73+
// Elmentjuk a nevsorrend szerinti helyet a place valtozoba.
74+
for( i = 0; i < API_tree_size; i++ ){
75+
76+
API_tree[ i ].place = i;
77+
78+
}
79+
80+
// Optimalizaljuk a sorrendet.
81+
optimise_api_tree();
82+
83+
if( debugPort ){
84+
85+
debugPort -> println( "Optimalizalas utan:" );
86+
for( i = 0; i < API_tree_size; i++ ){
87+
88+
debugPort -> printf( "%d. %s\r\n", i, API_tree[ i ].name );
89+
90+
}
91+
debugPort -> println();
92+
93+
}
94+
95+
96+
}
97+
98+
uint16_t Commander::find_api_index_by_place( uint16_t place ){
99+
100+
// Generic counter variable
101+
uint16_t i;
102+
103+
// Go through all commands
104+
for( i = 0; i < API_tree_size; i++ ){
105+
106+
// Check that if we found the desired command
107+
if( API_tree[i].place == place ){
108+
109+
// If we found it, return the index of it.
110+
return i;
111+
112+
}
113+
114+
}
115+
116+
// else return 0
117+
return 0;
118+
119+
}
120+
121+
void Commander::swap_api_elements( uint16_t index, uint16_t place ){
122+
123+
// Buffer that will temporarly hold an element.
124+
// This is required for a swap.
125+
API_t buffer;
126+
127+
// This variable will store the address of the element defined by the second argument( place ).
128+
uint16_t current_index;
129+
130+
// Find the index in the array by place of the 'i'-th element
131+
current_index = find_api_index_by_place( place );
132+
133+
// save the context of the 'i'-th element to the buffer
134+
buffer = API_tree[index];
135+
136+
// write the 'current_index'-th element to the 'i'-th element
137+
API_tree[index] = API_tree[current_index];
138+
139+
// write the buffer to the 'current_index'-th element
140+
API_tree[current_index] = buffer;
141+
142+
}
143+
144+
void Commander::optimise_api_tree(){
145+
146+
uint32_t i;
147+
148+
//API_t buffer;
149+
150+
// Stores the next elements address in the tree
151+
API_t *next;
152+
153+
// Stores the previous elements address in the tree
154+
API_t *prev;
155+
156+
// It will store string compersation result
157+
int32_t comp_res;
158+
159+
// recursive optimiser need to initialise 'API_cntr' to 0
160+
elementCounter = 0;
161+
162+
// recursively finds the order which is optimal for a balanced tree
163+
recursive_optimiser( 0, API_tree_size - 1 );
164+
165+
// The order is good, but the connection between the branches broken,
166+
// because we swapped the API_tree array elements.
167+
// To fix this problem we have to reinitialise the tree, and use
168+
// 'add_interpreter_command' function again for all elements.
169+
for( i = 1; i < API_tree_size; i++ ){
170+
171+
prev = &API_tree[ 0 ];
172+
comp_res = strcmp( prev -> name, API_tree[ i ].name );
173+
174+
(comp_res > 0) ? (next = (prev->left)) : ( next = (prev->right));
175+
176+
while( next != NULL ){
177+
178+
prev = next;
179+
comp_res = strcmp( prev -> name, API_tree[ i ].name );
180+
(comp_res > 0) ? (next = (prev->left)) : ( next = (prev->right));
181+
182+
}
183+
184+
( comp_res > 0 ) ? ( ( prev->left ) = &API_tree[ i ] ) : ( ( prev->right ) = &API_tree[ i ] );
185+
186+
}
187+
188+
}
189+
190+
// This function is used to order the elements in API_tree array to
191+
// get the fastest search speed
192+
// this function needs 'API_cntr' to be zeroed out before the first call
193+
void Commander::recursive_optimiser( int32_t start_index, int32_t stop_index ){
194+
195+
int32_t mid;
196+
197+
// End of recursive algorythm
198+
if( start_index > stop_index ){
199+
200+
return;
201+
202+
}
203+
204+
// Find the middle of the intervall
205+
mid = ( start_index + stop_index ) / 2;
206+
207+
// Put the right element to it's place
208+
swap_api_elements( elementCounter, mid );
209+
elementCounter++;
210+
211+
// Do some recursion for the other intervalls
212+
recursive_optimiser( start_index, mid - 1 );
213+
recursive_optimiser( mid + 1, stop_index );
214+
215+
216+
}
217+
218+
void Commander::executeCommand( char *cmd ){
219+
220+
// The begining of the argument list will be stored in this pointer
221+
char *arg;
222+
223+
// This variable tracks the command name length
224+
uint32_t cmd_name_cntr;
225+
226+
// If this flag is set, than the description message will be printed,
227+
// and the commands function won't be called.
228+
uint8_t show_description = 0;
229+
230+
API_t *commandData_ptr;
231+
232+
strncpy( tempBuff, cmd, COMMANDER_MAX_COMMAND_SIZE );
233+
234+
235+
// tempBuff is the address of the first character of the incoming command.
236+
// If we give arg variable the value stored in tempBuff means arg will point to
237+
// the first character of the command as well.
238+
arg = tempBuff;
239+
240+
// Reset the name counter before we start counting
241+
cmd_name_cntr = 0;
242+
243+
// Find the first space character or a string-end character.
244+
// At this time count how long is the command name( in characters )
245+
while( ( *arg != '\0' ) && ( *arg != ' ' ) && ( *arg != '?' ) ){
246+
247+
cmd_name_cntr++;
248+
arg++;
249+
250+
}
251+
252+
// If a space character found we have to terminate the string there.
253+
// It is important because strcmp function will search for string terminator
254+
// character, and this way we can separate the command name from its arguments.
255+
// This method has a downside. If we pass a const char as command
256+
// to the execution function it will try to overwrite a character in it.
257+
// It is impossible if the input string is constant and it will result hard fault!
258+
// To prevent this we nead a buffer. This is why INTERPRETER_BUFFER_SIZE macro has
259+
// been created. If you want to pass const chars to your interpreter directly, you
260+
// have to define INTERPRETER_BUFFER_SIZE with a resonable size.
261+
// But if you can prove it, that there is no chace in your program to use const chars,
262+
// you can comment out INTERPRETER_BUFFER_SIZE macro. This can save some space in your RAM.
263+
if( *arg == ' ' ){
264+
265+
*arg = '\0';
266+
arg++;
267+
268+
}
269+
270+
// The process is the same as above. The only difference is that this time
271+
// we have to set the show_description flag.
272+
else if( *arg == '?' ){
273+
274+
*arg = '\0';
275+
arg++;
276+
show_description = 1;
277+
278+
}
279+
280+
// Megnézzük, hogy a parancs létezik-e.
281+
commandData_ptr = (*this)[ tempBuff ];
282+
283+
if( commandData_ptr ){
284+
285+
// Because we have found the command in the API tree we have to choose
286+
// between description printing and executing.
287+
// If show_description flag is set, than we have to print the description.
288+
if( show_description ){
289+
290+
// Print the description text to the output channel.
291+
292+
response -> printf( "%s: %s\r\n", commandData_ptr -> name, commandData_ptr -> desc );
293+
294+
295+
}
296+
297+
// If show_description flag is not set, than we have to execute the commands function.
298+
else{
299+
300+
// Execute commands function.
301+
(commandData_ptr -> func)( arg, response );
302+
303+
}
304+
305+
}
306+
307+
else{
308+
309+
// If we went through the whole tree and we did not found the command in it,
310+
// we have to notice the user abut the problem. Maybe a Type-O
311+
response -> printf( "Command \'%s\' not found!!!\r\n", tempBuff );
312+
313+
}
314+
315+
}
316+
317+
void Commander::execute( char *cmd ){
318+
319+
response = &defaultResponse;
320+
executeCommand( cmd );
321+
322+
}
323+
324+
void Commander::execute( char *cmd, Serial *resp ){
325+
326+
serialResponse.select( resp );
327+
response = &serialResponse;
328+
executeCommand( cmd );
329+
330+
}
331+
332+
Commander::API_t* Commander::operator [] ( int i ){
333+
334+
if( i < 0 ){
335+
336+
return NULL;
337+
338+
}
339+
340+
return &API_tree[ i ];
341+
342+
}
343+
344+
Commander::API_t* Commander::operator [] ( char* name ){
345+
346+
// Stores the next elements address in the tree
347+
API_t *next;
348+
349+
// Stores the previous elements address in the tree
350+
API_t *prev;
351+
352+
// It will store string compersation result
353+
int8_t comp_res;
354+
355+
prev = &API_tree[ 0 ];
356+
357+
comp_res = strcmp( prev -> name, name );
358+
359+
(comp_res > 0) ? (next = (prev->left)) : ( next = (prev->right));
360+
361+
// Go through the binary tree until you find a match, or until you find the
362+
// end of the tree.
363+
while( ( comp_res !=0 ) && ( next != NULL ) ){
364+
365+
prev = next;
366+
comp_res = strcmp( prev -> name, name );
367+
(comp_res > 0) ? (next = (prev->left)) : ( next = (prev->right));
368+
369+
}
370+
371+
// If comp_res variable has a zero in it, that means in the last iteration
372+
// we had a match.
373+
if( comp_res == 0 ){
374+
375+
return prev;
376+
377+
}
378+
379+
return NULL;
380+
381+
}
382+
383+
Commander::API_t* Commander::operator [] ( const char* name ){
384+
385+
return (*this)[ (char*)name ];
386+
387+
}
388+

0 commit comments

Comments
 (0)