Skip to content

Commit 5f7c00a

Browse files
committed
AVR PROGMEM example
1 parent fa4bfbd commit 5f7c00a

File tree

1 file changed

+283
-0
lines changed

1 file changed

+283
-0
lines changed
Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
/*
2+
* Created on Oct. 02 2022
3+
*
4+
* Copyright (c) 2022 - Daniel Hajnal
5+
6+
* This file is part of the Commander-API project.
7+
* Modified 2022.10.02
8+
*
9+
* This is a simple example sketch that shows how
10+
* to use Commander-API library.
11+
*/
12+
13+
// Necessary includes
14+
#include "Commander-API.hpp"
15+
#include "Commander-IO.hpp"
16+
17+
// We have to create an object from Commander class.
18+
Commander commander;
19+
20+
// We have to create the prototypes functions for our commands.
21+
// The arguments have to be the same for all command functions.
22+
void cat_func( char *args, Stream *response );
23+
void dog_func( char *args, Stream *response );
24+
void sum_func( char *args, Stream *response );
25+
void led_func( char *args, Stream *response );
26+
27+
// To tell Commander how many commands we have, it is necessary
28+
// to create an array, that holds some data that represents our
29+
// commands. The type of this array must be Commander::API_t.
30+
// To simplify the command registration, there is a macro called
31+
// apiElement. This macro helps to add command data to this array.
32+
// -The first argument is the name of the command. Commander will
33+
// search the commands by its name.
34+
// -The second argument is the description for the command.
35+
// If you use the help command, or '?' character after the command
36+
// name, Commander will respond with its description.
37+
// -The third argument is the wrapper function, that has been defined
38+
// in the previous step.
39+
Commander::API_t API_tree[ 4 ];
40+
41+
void setup() {
42+
43+
apiElement_P( API_tree[ 0 ], "cat", "Description for cat command.", cat_func );
44+
apiElement_P( API_tree[ 1 ], "dog", "Description for dog command.", dog_func );
45+
apiElement_P( API_tree[ 2 ], "led", "Toggle the buit-in LED.", led_func );
46+
apiElement_P( API_tree[ 3 ], "sum", "This function sums two number from the argument list.", sum_func );
47+
48+
// Set the LED pin to output, and turn it off.
49+
pinMode( LED_BUILTIN, OUTPUT );
50+
digitalWrite( LED_BUILTIN, 0 );
51+
52+
// In this example, we will use the Serial for communication,
53+
// so we have to initialize it.
54+
Serial.begin( 115200 );
55+
56+
// If you using Atmega32U4, the code will wait, until
57+
// you open the serial port.
58+
while( !Serial );
59+
60+
// Step 1.
61+
Serial.println( "Step 1." );
62+
63+
// There is an option to attach a debug channel to Commander.
64+
// It can be handy to find any problems during the initialization
65+
// phase. In this example, we will use Serial for this.
66+
commander.attachDebugChannel( &Serial );
67+
68+
// At start, Commander does not know anything about our commands.
69+
// We have to attach the API_tree array from the previous steps
70+
// to Commander to work properly.
71+
commander.attachTree( API_tree );
72+
73+
// Step 2.
74+
Serial.println();
75+
Serial.println( "Step 2." );
76+
77+
// After we attached the API_tree, Commander has to initialize
78+
// itself for the fastest runtime possible. It creates a balanced
79+
// binary tree from the API_tree to boost the search speed.
80+
// This part uses some recursion, to make the code space small.
81+
// But recursion is a bit stack hungry, so please initialize
82+
// Commander at the beginning of your code to prevent stack-overlow.
83+
commander.init();
84+
85+
86+
// Example 1.
87+
Serial.println();
88+
Serial.println( F( "Example 1." ) );
89+
90+
// At this point, Commander is initialized and functional, so let's try it.
91+
// To execute a command, we have to use the execute command. Let's try
92+
// the LED command. This command just toggles the built-in LED.
93+
commander.execute( "led" );
94+
95+
// Example 2.
96+
Serial.println();
97+
Serial.println( F( "Example 2." ) );
98+
99+
// The most helpful command is help. It prints out all the available
100+
// commands.
101+
commander.execute( "help" );
102+
103+
// Example 3.
104+
Serial.println();
105+
Serial.println( F( "Example 3." ) );
106+
107+
// After the previous step, we can see, that we did not see anything.
108+
// This is because we did not give any response channel to the execute
109+
// function. Let's set Serial as response channel.
110+
commander.execute( "help", &Serial );
111+
112+
// Example 4.
113+
Serial.println();
114+
Serial.println( F( "Example 4." ) );
115+
116+
// To print the description data as well, we have to pass '-d' as argument
117+
// after the help command.
118+
commander.execute( "help -d", &Serial );
119+
120+
// Example 5.
121+
Serial.println();
122+
Serial.println( F( "Example 5." ) );
123+
// If we want to print out the description for only one command, we can
124+
// use the '?' operator after the command name.
125+
commander.execute( "led?", &Serial );
126+
127+
// Example 6.
128+
Serial.println();
129+
Serial.println( F( "Example 6." ) );
130+
// Now let's try the remaining functions.
131+
commander.execute( "cat", &Serial );
132+
commander.execute( "dog", &Serial );
133+
commander.execute( "sum", &Serial );
134+
135+
// Example 7.
136+
Serial.println();
137+
Serial.println( F( "Example 7." ) );
138+
// As we can see, the cat and dog functions worked as expected,
139+
// but the sum function give argument error. This happened
140+
// because we did not gave any arguments to that function.
141+
// Giving arguments to a command is very simple. You just have
142+
// to give an argument string after the command, separated by
143+
// a blank space. Commander will transfer the argument string
144+
// to the command's function. Let's try to sum 10 and 15.
145+
commander.execute( "sum 10 15", &Serial );
146+
147+
// Example 8.
148+
Serial.println();
149+
Serial.println( F( "Example 8." ) );
150+
// Now let's try to execute a command that does not exist,
151+
// and see what happens.
152+
commander.execute( "reboot", &Serial );
153+
154+
Serial.println();
155+
Serial.println( F( "Eaxmple session finished." ) );
156+
Serial.println( F( "Now you can play with commander as you like." ) );
157+
158+
}
159+
160+
// Continuous example.
161+
// In the loop function, there is a simple example to
162+
// read commands from Serial in runtime. You can use
163+
// the Serial monitor to try it. Set the line ending
164+
// to new-line and play with the commands.
165+
166+
// This is a buffer to hold the incoming command.
167+
char commandFromSerial[ 20 ];
168+
169+
// This variable tracks the location of the next free
170+
// space in the commandFromSerial buffer.
171+
uint8_t commandIndex = 0;
172+
173+
void loop() {
174+
175+
// Check if there is any data incoming.
176+
while( Serial.available() ){
177+
178+
// Read the next incoming character.
179+
char c = Serial.read();
180+
181+
// Every command from Serial is terminated with a new-line
182+
// character. If a new-line character arrives, we have to
183+
// terminate the string in the commandFromSerial buffer,
184+
// and execute it. After execution, we have to reset the
185+
// commandIndex counter to zero.
186+
if( c == '\n' ){
187+
188+
commandFromSerial[ commandIndex ] = '\0';
189+
commander.execute( commandFromSerial, &Serial );
190+
commandIndex = 0;
191+
192+
}
193+
194+
// If we have a carriage-return character we simply
195+
// ignore it.
196+
else if( c == '\r' ){
197+
continue;
198+
}
199+
200+
// Every other case we just put the data to the next
201+
// free space in the commandFromSerial buffer, increment
202+
// the commandIndex, and check if it wants to overflow.
203+
else{
204+
205+
commandFromSerial[ commandIndex ] = c;
206+
commandIndex++;
207+
if( commandIndex >= 20 ){
208+
commandIndex = 19;
209+
}
210+
211+
}
212+
213+
}
214+
215+
}
216+
217+
218+
/// This is an example function for the cat command
219+
void cat_func(char *args, Stream *response )
220+
{
221+
222+
response -> print( F( "Hello from cat function!\r\n" ));
223+
224+
}
225+
226+
/// This is an example function for the dog command
227+
void dog_func(char *args, Stream *response )
228+
{
229+
230+
response -> print( F( "Hello from dog function!\r\n" ));
231+
232+
}
233+
234+
/// This is an example function for the led command
235+
void led_func(char *args, Stream *response )
236+
{
237+
238+
digitalWrite( LED_BUILTIN, !digitalRead( LED_BUILTIN ) );
239+
240+
}
241+
242+
/// This is an example function for the sum command
243+
void sum_func(char *args, Stream *response )
244+
{
245+
246+
// These variables will hold the value of the
247+
// two numbers, that has to be summed.
248+
int a = 0;
249+
int b = 0;
250+
251+
// This variable will hold the result of the
252+
// argument parser.
253+
int argResult;
254+
255+
// This variable will hold the sum result.
256+
int sum = 0;
257+
258+
argResult = sscanf( args, "%d %d", &a, &b );
259+
260+
// We have to check that we parsed succesfully the two
261+
// numbers from the argument string.
262+
if( argResult != 2 ){
263+
264+
// If we could not parse two numbers, we have an argument problem.
265+
// We print out the problem to the response channel.
266+
response -> print( F( "Argument error! Two numbers required, separated with a blank space.\r\n" ) );
267+
268+
// Sadly we have to stop the command execution and return.
269+
return;
270+
271+
}
272+
273+
// Calculate the sum.
274+
sum = a + b;
275+
276+
// Print out the result.
277+
response -> print( a );
278+
response -> print( " + " );
279+
response -> print( b );
280+
response -> print( " = " );
281+
response -> println( sum );
282+
283+
}

0 commit comments

Comments
 (0)