Newer
Older
#include "cli.h"
void Cli::resetNextWord ()
{
_currentWordIndex = -1;
}
const char* Cli::findNextWord ()
{
if (_currentWordIndex >= 0)
// skip current word
while (_currentWordIndex < (int)_currentInput.length())
{
if (_currentInput[_currentWordIndex] == 32)
break;
_currentWordIndex++;
}
else
_currentWordIndex = 0;
// skip spaces
while (_currentWordIndex < (int)_currentInput.length())
{
if (_currentInput[_currentWordIndex] != 32)
break;
_currentWordIndex++;
}
const char* ret = _currentWordIndex < (int)_currentInput.length()? _currentInput.c_str() + _currentWordIndex: nullptr;
for (_currentWordEndIndex = _currentWordIndex; _currentInput.c_str()[_currentWordEndIndex] > 32; _currentWordEndIndex++);
#if 0
if (ret)
Serial.printf("# found new start of word '%s'\n", ret);
else
Serial.printf("# no more word?\n");
#endif
return ret;
}
void Cli::copyNextToTemp ()
{
if (!findNextWord())
{
_temp = emptyString;
return;
}
int start = _currentWordIndex;
int end = _currentWordEndIndex;
if (start < end)
_temp = _currentInput.substring(start, end);
else
_temp.clear();
}
bool Cli::kw (const __FlashStringHelper* keyWord, const char* input)
{
// return true if input matches keyWord
auto len = strlen_P((PGM_P)keyWord);
return len && strncasecmp_P((PGM_P)keyWord, input, len) == 0;
}
bool Cli::kw (const __FlashStringHelper* keyWord)
{
return kw(keyWord, _currentInput.c_str() + _currentWordIndex);
}
void Cli::syntax (const __FlashStringHelper* cmd)
{
syntax((PGM_P)cmd);
}
void Cli::syntax (const char* cmd)
{
if (!cmd || kw(F("AT"), cmd)) Serial.printf("%sAT -> OK\n", _msgHeader);
if (!cmd || kw(F("HELP"), cmd)) Serial.printf("%sHELP [CMD]\n", _msgHeader);
if (!cmd || kw(F("RAT"), cmd)) Serial.printf("%sRAT [ C <rate> [<unit>] ] - set or show rate ([UM]/MM/UH/MH)\n", _msgHeader);
if (!cmd || kw(F("VOL"), cmd)) Serial.printf("%sVOL [ <vol> | <unit> ] - set the volume to exchange in mL\n", _msgHeader);
if (!cmd || kw(F("RVOL"), cmd)) Serial.printf("%sRVOL <vol> - set relative volume to exchange in mL\n", _msgHeader);
if (!cmd || kw(F("MM"), cmd)) Serial.printf("%sMM [ <len> ] - set final position in mm\n", _msgHeader);
if (!cmd || kw(F("RMM"), cmd)) Serial.printf("%sRMM <len> - set relative distance to browse in mm\n", _msgHeader);
if (!cmd || kw(F("DIA"), cmd)) Serial.printf("%sDIA [ <dia> ] - set or show inside syringe diameter in mm\n", _msgHeader);
if (!cmd || kw(F("ACC"), cmd)) Serial.printf("%sACC [ <mm/s/s> ] - set or show acceletaration (mm/s/s) (0<=>oo)\n", _msgHeader);
if (!cmd || kw(F("RVM"), cmd)) Serial.printf("%sRVM [ <M4|M5> ] - set or show auger size\n", _msgHeader);
if (!cmd || kw(F("DIR"), cmd)) Serial.printf("%sDIR [ INF | WDR ] - set or show direction (INFuse / WithDRaw)\n", _msgHeader);
if (!cmd || kw(F("FIL"), cmd)) Serial.printf("%sFIL - start filling using direction at rate for volume\n", _msgHeader);
if (!cmd || kw(F("STP"), cmd)) Serial.printf("%sSTP - stop\n", _msgHeader);
if (!cmd || kw(F("DIS"), cmd)) Serial.printf("%sDIS - show volume dispensed\n", _msgHeader);
if (!cmd || kw(F("ZERO"), cmd)) Serial.printf("%sZERO - go to stopper\n", _msgHeader);
if (!cmd || kw(F("SET0"), cmd)) Serial.printf("%sSET0 - change ZERO to current position\n", _msgHeader);
if (!cmd || kw(F("NLCK"), cmd)) Serial.printf("%sNLCK - try to get out from stopper\n", _msgHeader);
if (!cmd || kw(F("CLKW"), cmd)) Serial.printf("%sCLKW [0 | 1] - 1: push = rotate clockwise\n", _msgHeader);
if (!cmd || kw(F("CONF"), cmd)) Serial.printf("%sCONF - show configuration\n", _msgHeader);
Malaurie Bernard
committed
if (!cmd || kw(F("FS-LS"), cmd)) Serial.printf("%sFS-LS - show all the files\n", _msgHeader);
if (!cmd || kw(F("FS-CAT"), cmd)) Serial.printf("%sFS-CAT - print a file\n", _msgHeader);
if (!cmd || kw(F("FS-SAVE"), cmd)) Serial.printf("%sFS-SAVE - save the files\n", _msgHeader);
if (!cmd || kw(F("FS-LOAD"), cmd)) Serial.printf("%sFS-LOAD - load the files\n", _msgHeader);
}
void Cli::answer (bool ok, const String& error_message) const
{
if (!ok && error_message.length())
Serial.printf(" (%s)", error_message.c_str());
Serial.printf("\n");
void Cli::check_emergency ()
if (syringe_filled.get_emergency())
Serial.printf("%sin EMERGENCY state, try NLCK command\n", _msgHeader);
}
void Cli::loop (Stream& input)
{
while (true)
{
if (!input.available())
return;
int c = input.read();
if (c == 13)
break;
if (c >= 32 && c <= 127)
_currentInput += (char)c;
resetNextWord();
if (findNextWord())
{
if (kw(F("AT")))
{
}
else if (kw(F("HELP")))
{
copyNextToTemp();
if (_temp.length())
syntax(_temp.c_str());
else
else if (kw(F("RAT"))) //*******************RATE*******************//
copyNextToTemp();
if (_temp.equalsIgnoreCase(F("C")))
{
copyNextToTemp();
syringe_filled.set_exchange_throughput_uL_per_min(atof(_temp.c_str()));
copyNextToTemp();
if (_temp.equalsIgnoreCase(F("us")))
syringe_filled.set_exchange_throughput_uL_per_min(syringe_filled.get_exchange_throughput_uL_per_min()/60);
else if (_temp.equalsIgnoreCase(F("ms")))
syringe_filled.set_exchange_throughput_uL_per_min(syringe_filled.get_exchange_throughput_uL_per_min()*1000/60);
else if (_temp.equalsIgnoreCase(F("um")))
;
else if (_temp.equalsIgnoreCase(F("mm")))
syringe_filled.set_exchange_throughput_uL_per_min(syringe_filled.get_exchange_throughput_uL_per_min()*1000);
else if (_temp.equalsIgnoreCase(F("uh")))
syringe_filled.set_exchange_throughput_uL_per_min(syringe_filled.get_exchange_throughput_uL_per_min()/60);
else if (_temp.equalsIgnoreCase(F("mh")))
syringe_filled.set_exchange_throughput_uL_per_min(syringe_filled.get_exchange_throughput_uL_per_min()*1000/60);
else
syringe_filled.set_exchange_throughput_uL_per_min(-1);
answer(syringe_filled.check_configuration(), F("invalid 'RAT C rate uL'"));
answer(false, F("RAT must be followed by C"));
Serial.printf("%sRAT: %g ul/mn\n", _msgHeader, syringe_filled.get_exchange_throughput_uL_per_min());
else if (kw(F("VOL"))) //*******************EXCHANGE_VOLUME*******************//
copyNextToTemp();
while (_temp.length())
{
if (isdigit(_temp[0]))
{
syringe_filled.set_exchange_volume_mL(syringe_filled.distance_mm_to_volume_mL(syringe_filled.step_to_mm(syringe_filled.where_step())) - stof(_temp.c_str()));
syringe_filled.save_json();
Serial.println("ok");
}
else if (_temp.equalsIgnoreCase(F("ul")))
;
else if (_temp.equalsIgnoreCase(F("ml")))
syringe_filled.set_exchange_volume_mL(syringe_filled.get_exchange_volume_mL()*1000);
else if (_temp.equalsIgnoreCase(F("cl")))
syringe_filled.set_exchange_volume_mL(syringe_filled.get_exchange_volume_mL()*10000);
else if (_temp.equalsIgnoreCase(F("dl")))
syringe_filled.set_exchange_volume_mL(syringe_filled.get_exchange_volume_mL()*100000);
else if (_temp.equalsIgnoreCase(F("l")))
syringe_filled.set_exchange_volume_mL(syringe_filled.get_exchange_volume_mL()*1000000);
syringe_filled.save_json();
answer(syringe_filled.check_configuration(), F("invalid volume or volume unit"));
copyNextToTemp();
}
else if (kw(F("RVOL"))) //*******************RELATIVE_EXCHANGE_VOLUME*******************//
syringe_filled.reset_position();
copyNextToTemp();
while (_temp.length())
{
if (isdigit(_temp[0]) || _temp[0] == '-')
syringe_filled.set_exchange_volume_mL(atof(_temp.c_str()));
answer(syringe_filled.check_configuration(), F("invalid exchange volume"));
Serial.printf("%sRVOL: %g ml (target)\n", _msgHeader, syringe_filled.get_exchange_volume_mL());
else if (kw(F("MM"))) //*******************DISTANCE_TO_ZERO*******************//
copyNextToTemp();
if (_temp.length())
{
if (isdigit(_temp[0]) || _temp[0] == '-')
syringe_filled.set_exchange_volume_mL(syringe_filled.distance_mm_to_volume_mL(syringe_filled.step_to_mm(syringe_filled.where_step())) + syringe_filled.distance_mm_to_volume_mL(atof(_temp.c_str())));
answer(syringe_filled.check_configuration(), F("invalid length"));
syringe_filled.save_json();
Serial.printf("%sMM: %g ml (%g mm) (target)\n", _msgHeader, syringe_filled.get_exchange_volume_mL(), syringe_filled.volume_mL_to_distance_mm(syringe_filled.get_exchange_volume_mL()));
else if (kw(F("RMM"))) //*******************RELATIVE_DISTANCE*******************//
copyNextToTemp();
if (_temp.length())
{
if (isdigit(_temp[0]) || _temp[0] == '-')
syringe_filled.set_exchange_volume_mL(syringe_filled.distance_mm_to_volume_mL(atof(_temp.c_str())));
answer(syringe_filled.check_configuration(), F("invalid exchange length"));
syringe_filled.save_json();
Serial.printf("%sRMM: %g ml (%g mm) (target)\n", _msgHeader, syringe_filled.get_exchange_volume_mL(), syringe_filled.volume_mL_to_distance_mm(syringe_filled.get_exchange_volume_mL()));
else if (kw(F("DIA"))) //*******************INTERNAL_DIAMETER*******************//*
copyNextToTemp();
syringe.set_internal_diameter_mm("cli", atof(_temp.c_str()));
syringe.save_json();
answer( syringe.check_configuration("cli"), F("invalid diameter"));
Serial.printf("%sDIA: %g mm\n", _msgHeader, syringe.get_internal_diameter_mm("cli"));
{
syringe_filled.set_lead_screw_pitch_mm(0.7);
syringe_filled.save_json();
}
{
syringe_filled.set_lead_screw_pitch_mm(0.8);
syringe_filled.save_json();
}
else if (_temp.length() > 0)
answer(false, F("invalid auger size: M4 or M5 are accepted"));
Serial.printf("%sRVM: %g mm per revolution\n", _msgHeader, syringe_filled.get_lead_screw_pitch_mm());
else if (kw(F("ACC"))) //*******************ACCELERATION*******************//
syringe_filled.set_retain_acceleration_mm_per_sec_per_sec(atof(_temp.c_str()));
Serial.printf("%sACC: %g mm per second per second\n", _msgHeader, syringe_filled.get_retain_acceleration_mm_per_sec_per_sec());
else if (kw(F("DIR"))) //*******************DIRECTION*******************//
copyNextToTemp();
if (_temp.length())
{
if (_temp.equalsIgnoreCase(F("inf")))
syringe_filled.set_push(true);
syringe_filled.set_push(false);
answer(syringe_filled.check_configuration(), F("invalid direction -> INF | WDR"));
syringe_filled.get_push()? "INFuse": "WithDRaw");
else if (kw(F("FIL"))) //*******************MOUVEMENT*******************//
check_emergency();
answer(true);
}
else if (kw(F("STP")))
{
syringe_filled.stop();
Malaurie Bernard
committed
syringe_filled.reset_position();
else if (kw(F("DIS"))) //*******************DISTANCE_PARCOURU*******************//
syringe_filled.get_push()? syringe_filled.distance_mm_to_volume_mL(syringe_filled.step_to_mm(syringe_filled.where_step())): 0,
syringe_filled.get_push()? 0 : syringe_filled.distance_mm_to_volume_mL(syringe_filled.step_to_mm(syringe_filled.where_step())));
else if (kw(F("ZERO"))) //*******************ZERO*******************//
check_emergency();
syringe_filled.go_to_limit_switch();
else if (kw(F("NLCK"))) //*******************RUN_FROM_EMERGENCY*******************//
syringe_filled.run_from_emergency();
}
else if (kw(F("CLKW"))) //*******************CLOCKWISE_EQUALS_PUSH*******************//
copyNextToTemp();
if (_temp.length() == 1)
{
if (_temp[0] == '0' || _temp[0] == '1')
{
syringe_filled.set_clockwise_equals_push(_temp[0] == '1');
answer(true);
}
else
answer(false, F("CLKW: invalid argument"));
}
Serial.printf("%sCLKW: push %sclockwise\n", _msgHeader, syringe_filled.get_clockwise_equals_push()? "": "anti-");
else if (kw(F("CONF"))) //*******************SHOW_CONFIGURATION*******************//
Malaurie Bernard
committed
syringe_filled.show_configuration();
Malaurie Bernard
committed
else if (kw(F("FS-LS"))) //*******************SHOW_ALL_THE_FILES*******************//
Malaurie Bernard
committed
else if (kw(F("FS-CAT"))) //*******************PRINT_A_FILE*******************//
{
copyNextToTemp();
if (_temp.length() > 0)
{
cat(_temp.c_str(), &Serial);
answer(true);
}
else
answer(false);
}
else if (kw(F("FS-SAVE"))) //*******************SAVE_THE_JSON_FILES*******************//
syringe.save_json();
syringe_filled.save_json();
Malaurie Bernard
committed
answer(true);
}
else if (kw(F("FS-LOAD"))) //*******************LOAD_THE_JSON_FILES*******************//
Malaurie Bernard
committed
{
syringe.load_json();
syringe_filled.load_json();
Malaurie Bernard
committed
answer(true);
Serial.printf("%sinvalid command '%s'\n", _msgHeader, _currentInput.c_str() + _currentWordIndex);
if (findNextWord())
Serial.printf("%sgarbage at end of line: '%s'\n", _msgHeader, _currentInput.c_str() + _currentWordIndex);
resetNextWord();
_currentInput.clear();
}