First, you could use a string for the commands. You just need to ensure there is some special char to mark the end of a command - like the newline char. Read the input from the port one char at a time, building the string as you go:
char buffer[256];
uint16_t buffer_index = 0;
void loop() {
while (Serial.available()) {
int c = Serial.read();
if ('\n' == c) {
buffer[buffer_index] = 0; // Append EOS
// Complete message - do something
buffer_index = 0; // Reset, ready for next message
}
else {
// Append char to end of buffer
buffer[buffer_index++] = c;
}
// Check for overflow
if (256 == buffer_index) {
buffer_index = 0;
}
}
}
There are plenty of examples like this on this site.
Next, I don't recommend using an if
statement with a hundred or more conditions. Instead, you can store pointers to each function in an array:
// Use a typedef to simplfy
typedef void (*function_type)(); // A function with no params and no return, change as needed
// Fixed array size
const int max_functions = 200;
// Create an array of 200 function pointers
function_type all_functions[max_functions] = {0};
So to call function #11:
all_functions[10]();
Now you just need a way to marry the function pointers to a name. A hash table could work here. A hash function converts a string to a number. There are lots of examples on the web. Here's one:
uint16_t djb2_hash(const char *str)
{
unsigned long hash = 5381;
int c;
while (0 != (c = *str++)) {
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
}
// Note: we use the mod operator to make sure value
// is less than array size
return hash % max_functions;
}
Create two functions, one to add a function and one to retreive:
bool add_function(const char *name, function_type f)
{
// Convert name to number
uint16_t index = djb2_hash(name); // 0 <= index <= max_functions
if (NULL != all_functions[index]) {
// There is already a function stored at this index
Serial.print("Adding ");
Serial.print(name);
Serial.print("failed. index = ");
Serial.println(index);
return false;
}
else {
// Store the function in the array
all_functions[index] = f;
return true;
}
}
bool run_function(const char *name)
{
uint16_t index = djb2_hash(name);
if (NULL == all_functions[index]) {
// Name not found
return false;
}
else {
// Call the function
all_functions[index]();
return true;
}
}
Last, create some functions and add to hash table:
void f1() {Serial.println("F1");}
void f2() {Serial.println("F2");}
void f3() {Serial.println("F3");}
void setup() {
Serial.begin(9600);
add_function("F1", f1);
add_function("F2", f2);
add_function("F3", f3);
}
All that's left is to modify loop()
to call the functions when a complete message is received.
void loop() {
while (Serial.available()) {
int c = Serial.read();
if ('\n' == c) {
buffer[buffer_index] = 0;
run_function(buffer);
buffer_index = 0;
}
else {
buffer[buffer_index++] = c;
}
// Check for overflow
if (256 == buffer_index) {
buffer_index = 0;
}
}
}
If you enter "F1", "F2", or "F3" in the serial monitor, those functions should execute. Just make sure you change the serial monitor to append a newline.
Some notes: the hash function may not create a unique id for each string. You need to handle this situation. Also, the names are case sensitive. If you don't want that, convert everything to all upper case or all lower.
char
can be 256 different values. However, data is read in one byte at a time. You may want to develop your own communication protocol to send multiple bytes. It doesn't even have to be complicated: just read x bytes, and then stop.strcmp()
to evaluate the contents. Also, indent your code.