Skip to content

Commit ce52535

Browse files
Issue simplefoc#46: motor.command() and CRLF
The eol character is now configurable The user can now actuvate echo feedback to see what he is typing I also removed a duplication in two run() overload, while fixing what I think was a mistake by enforcing the use of the provided argument Stream& even if the ctor one is not null. Lastly, I warn the user if \n is configured but \r is detected (only in user friendly mode) All the past code should work as before (no API change required)
1 parent ee2dfde commit ce52535

File tree

2 files changed

+53
-34
lines changed

2 files changed

+53
-34
lines changed

src/communication/Commander.cpp

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
#include "Commander.h"
22

33

4-
Commander::Commander(Stream& serial){
4+
Commander::Commander(Stream& serial, char eol, bool echo){
55
com_port = &serial;
6+
this->eol = eol;
7+
this->echo = echo;
68
}
7-
Commander::Commander(){
8-
// do nothing
9+
Commander::Commander(char eol, bool echo){
10+
this->eol = eol;
11+
this->echo = echo;
912
}
1013

1114

@@ -19,33 +22,24 @@ void Commander::add(char id, CommandCallback onCommand, char* label ){
1922

2023
void Commander::run(){
2124
if(!com_port) return;
22-
// a string to hold incoming data
23-
while (com_port->available()) {
24-
// get the new byte:
25-
received_chars[rec_cnt] = (char)com_port->read();
26-
// end of user input
27-
if (received_chars[rec_cnt++] == '\n') {
28-
// execute the user command
29-
run(received_chars);
30-
31-
// reset the command buffer
32-
received_chars[0] = 0;
33-
rec_cnt=0;
34-
}
35-
}
25+
run(*com_port, eol);
3626
}
3727

38-
void Commander::run(Stream& serial){
28+
void Commander::run(Stream& serial, char eol){
3929
Stream* tmp = com_port; // save the serial instance
40-
// use the new serial instance to output if not available the one linked in constructor
41-
if(!tmp) com_port = &serial;
30+
char eol_tmp = this->eol;
31+
this->eol = eol;
32+
com_port = &serial;
4233

4334
// a string to hold incoming data
4435
while (serial.available()) {
4536
// get the new byte:
46-
received_chars[rec_cnt] = (char)serial.read();
37+
int ch = serial.read();
38+
received_chars[rec_cnt++] = (char)ch;
4739
// end of user input
48-
if (received_chars[rec_cnt++] == '\n') {
40+
if(echo)
41+
print((char)ch);
42+
if (isSentinel(ch)) {
4943
// execute the user command
5044
run(received_chars);
5145

@@ -56,11 +50,15 @@ void Commander::run(Stream& serial){
5650
}
5751

5852
com_port = tmp; // reset the instance to the internal value
53+
this->eol = eol_tmp;
5954
}
6055

6156
void Commander::run(char* user_input){
6257
// execute the user command
6358
char id = user_input[0];
59+
60+
61+
6462
switch(id){
6563
case CMD_SCAN:
6664
for(int i=0; i < call_count; i++){
@@ -71,7 +69,7 @@ void Commander::run(char* user_input){
7169
}
7270
break;
7371
case CMD_VERBOSE:
74-
if(user_input[1] != '\n') verbose = (VerboseMode)atoi(&user_input[1]);
72+
if(user_input[1] != eol) verbose = (VerboseMode)atoi(&user_input[1]);
7573
printVerbose(F("Verb:"));
7674
switch (verbose){
7775
case VerboseMode::nothing:
@@ -84,7 +82,7 @@ void Commander::run(char* user_input){
8482
}
8583
break;
8684
case CMD_DECIMAL:
87-
if(user_input[1] != '\n') decimal_places = atoi(&user_input[1]);
85+
if(user_input[1] != eol) decimal_places = atoi(&user_input[1]);
8886
printVerbose(F("Decimal:"));
8987
println(decimal_places);
9088
break;
@@ -105,7 +103,7 @@ void Commander::motor(FOCMotor* motor, char* user_command) {
105103
char sub_cmd = user_command[1];
106104
int value_index = (sub_cmd >= 'A' && sub_cmd <= 'Z') ? 2 : 1;
107105
// check if get command
108-
bool GET = user_command[value_index] == '\n';
106+
bool GET = isSentinel(user_command[value_index]);
109107
// parse command values
110108
float value = atof(&user_command[value_index]);
111109

@@ -306,7 +304,7 @@ void Commander::motor(FOCMotor* motor, char* user_command) {
306304
case SCMD_SET:
307305
if(!GET) motor->monitor_variables = (uint8_t) 0;
308306
for(int i = 0; i < 7; i++){
309-
if(user_command[value_index+i] == '\n') break;
307+
if(isSentinel(user_command[value_index+i])) break;
310308
if(!GET) motor->monitor_variables |= (user_command[value_index+i] - '0') << (6-i);
311309
print( (user_command[value_index+i] - '0') );
312310
}
@@ -326,7 +324,7 @@ void Commander::motor(FOCMotor* motor, char* user_command) {
326324

327325
void Commander::pid(PIDController* pid, char* user_cmd){
328326
char cmd = user_cmd[0];
329-
bool GET = user_cmd[1] == '\n';
327+
bool GET = isSentinel(user_cmd[1]);
330328
float value = atof(&user_cmd[1]);
331329

332330
switch (cmd){
@@ -363,7 +361,7 @@ void Commander::pid(PIDController* pid, char* user_cmd){
363361

364362
void Commander::lpf(LowPassFilter* lpf, char* user_cmd){
365363
char cmd = user_cmd[0];
366-
bool GET = user_cmd[1] == '\n';
364+
bool GET = isSentinel(user_cmd[1]);
367365
float value = atof(&user_cmd[1]);
368366

369367
switch (cmd){
@@ -379,11 +377,26 @@ void Commander::lpf(LowPassFilter* lpf, char* user_cmd){
379377
}
380378

381379
void Commander::scalar(float* value, char* user_cmd){
382-
bool GET = user_cmd[0] == '\n';
380+
bool GET = isSentinel(user_cmd[0]);
383381
if(!GET) *value = atof(user_cmd);
384382
println(*value);
385383
}
386384

385+
bool Commander::isSentinel(char ch)
386+
{
387+
if(ch == eol)
388+
return true;
389+
else if (ch == '\r')
390+
{
391+
if(verbose == VerboseMode::user_friendly)
392+
{
393+
print(F("Warning! \\r detected but is not configured as end of line sentinel, which is configured as ascii code '"));
394+
print(int(eol));
395+
print("'\n");
396+
}
397+
}
398+
return false;
399+
}
387400

388401
void Commander::print(const int number){
389402
if( !com_port || verbose == VerboseMode::nothing ) return;

src/communication/Commander.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ class Commander
3838
* Also if the function run() is used it uses this serial instance to read the serial for user commands
3939
*
4040
* @param serial - Serial com port instance
41+
* @param eol - the end of line sentinel character
42+
* @param echo - echo last typed character (for command line feedback)
4143
*/
42-
Commander(Stream &serial);
43-
Commander();
44+
Commander(Stream &serial, char eol = '\n', bool echo = false);
45+
Commander(char eol = '\n', bool echo = false);
4446

4547
/**
4648
* Function reading the serial port and firing callbacks that have been added to the commander
@@ -61,9 +63,10 @@ class Commander
6163
* '#' - Number of decimal places
6264
* '?' - Scan command - displays all the labels of attached nodes
6365
*
64-
* @param reader - Stream to read user input
66+
* @param reader - temporary stream to read user input
67+
* @param eol - temporary end of line sentinel
6568
*/
66-
void run(Stream &reader);
69+
void run(Stream &reader, char eol = '\n');
6770
/**
6871
* Function reading the string of user input and firing callbacks that have been added to the commander
6972
* once the user has requested them - when he sends the command
@@ -91,7 +94,8 @@ class Commander
9194

9295
// monitoring functions
9396
Stream* com_port = nullptr; //!< Serial terminal variable if provided
94-
97+
char eol = '\n'; //!< end of line sentinel character
98+
bool echo = false; //!< echo last typed character (for command line feedback)
9599
/**
96100
*
97101
* FOC motor (StepperMotor and BLDCMotor) command interface
@@ -194,6 +198,7 @@ class Commander
194198
* @param message - number to be printed
195199
* @param newline - if needs lewline (1) otherwise (0)
196200
*/
201+
197202
void print(const float number);
198203
void print(const int number);
199204
void print(const char* message);
@@ -206,6 +211,7 @@ class Commander
206211
void println(const char message);
207212

208213
void printError();
214+
bool isSentinel(char ch);
209215
};
210216

211217

0 commit comments

Comments
 (0)