UP | HOME

Shell per ESP 32

Table of Contents

Premessa

Scopo del codice disponibile al link e' quello di realizzare una shell per le board esp32 / arduino che metta ha disposizione i seguenti comandi di modo da rendere gestibile la board a runtime permettendo di utilizzare l'ambiente di shell nei seguenti modi :

  • modo interattivo - i comandi possono essere digitati direttamente da linea di comando collegando la board tramite seriale;
  • modo trasparente - i comandi di shell posso essere richiamati all'internoi del software con possibilita' che l'output di un comando venga trasferito in memoria.

Inoltre la shell mette a disposizione il comando macro che permette di eseguire file contenenti altri comandi di shell.

Introduzione

Il codice e' stato implementato utilizzando Visual Studio per Linux con l'estensione platformio e lo schma di test e' quello indicato nella figura di seguito in cui e' inserito un sensore di tipo DHT22 per la misura di temperatura ed umidita' ed un pulsante che pemette di accedere all'ambiente di shell. Inoltre sulla board e' in funzione un web server che rimane attivo anche quando l'ambiente di shell e' utilizzata in modo interattivo. Per una panoramica piu veloce si consiglia la visione del seguente video.

schema.png

Figure 1: Schema di test

Classe Input

Questa classe permette la gestione dell'input in modo simile a quello di una qualsiasi shell inoltre si definisce un overload degli operatori di redirezione per rendere compatibile l'oggetto nativo di arduino di tipo String con quello del cpp di tipo string nonche' di effettuare concatenazione tra gli streaming acquisiti.

Metodi pubblici della classe

input();                                                  // costruttore di default
void setMode(boolean __set__) { __mode__ = __set__; }     // imposta lo stato della classe
void setEcho(boolean __set__) { __HideEcho__ = __set__; } // imposta il modo di echo dei caratteri
void read_Rx();                                           // legge i caratteri da tastiera
void rtrim();                                             // cacella i caratteri a dx della stringa con il match della stringa WHITESPACE
void ltrim();                                             // cancella i caratteri a sx della stringa con il match della stringa WHITESPACE
void trim();                                              // cancella i caratteri a sx e a dx della stringa con il match della stringa WHITESPACE
int stoi() const;                                         // converte la stringa in un intero
void clear()                                              // svuota il contenuto utile dell'oggetto
{

Metodi privati della classe

/* utility per la gestione della classe */
std::string STR2str(String);                          // conversione da String a std::string
String str2STR(std::string);                          // conversione da std::string a String
boolean isMode() { return __mode__; }                 // ritorna lo stato della classe
const String &getSTR() const { return __ROW__; }      // conversione da std::string a String

Proprieta' della classe

boolean __mode__;                             // indica se il sistema si trova in modalita' input mode
boolean __HideEcho__;                         // se true maschera i caratteri digitati
std::string __row__;                          // riga digitata - oggetto di tipo string
const std::string WHITESPACE = " \n\r\t\f\v"; // stringa di escape
String __ROW__;                               // riga digitata - oggetto di tipo String
int __SesTimeout__;                           // tempo di time out

Overloading

I seguenti overload permettono di utilizzare l'oggetto di tipo input come se fosse nativo del C++ e di assegnare oggetti di tipo String nativo di ESP a oggetti di tipo string del C++

// friend   istream& operator>>(istream& is, input& __obj__){ __obj__.__row__=__obj__.STR2str();return is;}
// sovracaricamento dell'operatore  >>
friend std::istream &operator>>(std::istream &is, input &__obj__)
{
  __obj__.read_Rx();
  return is;
}                                                                                                   // sovracaricamento dell'operatore  >>
friend std::ostream &operator<<(std::ostream &os, input &__obj__) { return os << __obj__.__row__; } // sovracaricamento dell'operatore <<

friend void operator>>(const std::string &lhs, input &__obj__) { __obj__.__row__ = lhs; } // sovracaricamento operator >> string -> input

friend std::string &operator+=(std::string &lhs, const input &__obj__) { return lhs += __obj__.__row__; } // sovracaricamento operator string += input
friend String &operator+=(String &LHS, const input &__obj__) { return LHS += __obj__.__ROW__; }           // sovracaricamento operator String += input

friend boolean operator==(const std::string &lhs, const input &__obj__) { return lhs == __obj__.__row__; } // sovracaricamento operator string==input
friend boolean operator==(const input &__obj__, const std::string &rhs) { return rhs == __obj__.__row__; } // sovracaricamento operator input==string

friend boolean operator==(const String &LHS, const input &__obj__) { return LHS == __obj__.__ROW__; } // sovracaricamento operator String==input
friend boolean operator==(const input &__obj__, const String &RHS) { return RHS == __obj__.__ROW__; } // sovracaricamento operator input==String

/*
La dichiarazione operator string const &() const { return getstr(); } all'interno di una classe è un esempio di operatore di
 conversione personalizzato. Questo operatore consente di definire una conversione implicita da un oggetto di quella classe a
 un altro tipo specificato, in questo caso string (ovvero std::string).

Vediamo in dettaglio cosa fa questa dichiarazione:

operator string const &(): Questo dichiara un operatore di conversione. La keyword operator indica che stai definendo un
operatore. string è il tipo di dati di destinazione al quale stai cercando di convertire l'oggetto. const & indica che
il risultato della conversione è una costante riferita (riferimento costante) a un oggetto di tipo string.

const: Questa è una parte della dichiarazione che indica che il riferimento restituito è costante, il che significa che
non puoi modificare l'oggetto attraverso questo riferimento.

&(): Questa parte della dichiarazione definisce l'operatore di conversione come una funzione senza argomenti, quindi la
sintassi () indica che è una funzione. L'operatore restituirà un riferimento al tipo di dati specificato, in questo
caso string.

{ return getstr(); }: Questo è il corpo dell'operatore di conversione. getstr() è un metodo della classe input che
restituisce il contenuto della variabile privata __row__ come string. L'operatore di conversione utilizza questo
metodo per ottenere il valore da convertire in string e quindi restituisce il riferimento a tale valore.

In sintesi, l'operatore di conversione operator string const &() ti consente di convertire un oggetto della classe input
in un oggetto di tipo string utilizzando una conversione implicita. Ad esempio, se hai un oggetto input chiamato myInput,
puoi assegnarlo a una variabile string come se fosse già un oggetto di tipo string. Questo offre una maggiore comodità e
flessibilità nell'uso degli oggetti della classe input.
*/
operator String const &() const { return getSTR(); }      // permette assegmamenti del tipo String=input
operator std::string const &() const { return getstr(); } // permette assegmamenti del tipo string=input

// ------------------------------------------------------------------------------------------------------------------------------------------------------------------

input &operator=(const std::string &str) // overload operatore per assegnazioni del tipo input=string
{
  this->clear();
  __row__ = str;
  __ROW__ = str2STR(__row__);
  return *this; // Restituiamo l'oggetto corrente per supportare gli assegnamenti concatenati
}

Acquisizione dalla seriale

il seguente medoto viene utilizzato quando si acquigisce uno stream da seriale ( uso della shell in modo interattivo ).

/*

  SerSrvMenu -  Serial Communication, get characters from  Serial (USB) Port
  ------------------------------------------------------------------------


  La funzione permette permette di acquisire una stringa digitata da tastiera.
  I caratteri digitati vengono memorizzati nell'array di carartteri
  receivedchars[] terminato dal carattere '\0' quando si preme il gtasto return.
  Per evitare lo sconfinamento dei limiti dell'array ad ogni pressione del tasto
  si incremnta l'indice dell'array che quando raggiunge il limite massimo viene
  decrementato di uno di modo che nell'ultima posizione ci sia sempre l'ultimo
  carattere digitato che alla pressione del tasto return viene sostituito dal
  carattere di escape '\0'.

  Inoltre vi è un controlllo della durata del tempo di acquisiszione con il
  contatore che viene resettato ad ogni pressione di tasto.

  Infine l'impostazione a true della variabile HideEcho implica che il carattere
  digitato viene visualizzato con il carattere *.


  Ser_Rx()
  |
  +---[controllo del timeout]
  |
  +---[blocco di lettura]{
  |
  +----[blocco di acquisizione]

*/
void input::read_Rx()
{
  unsigned long SessStart = millis(); // durata del timeout
  char endMarker1 = '\r';             // Some terminal client apps send a CR
  char endMarker2 = '\n';             // Others just a LF character, therefore we need to check for both
  char rc;                            // carattere digitato
  const byte numChars = MaxSerRx;
  boolean newData = false;
  static byte ndx = 0;          // inizializza l'indice dell'array dei caratteri digitati utilizzato nella funzione read_RX
  char receivedChars[numChars]; // an array to store the received data

  // Serial.println(numChars);

  if (__row__.length() > 0)
  {
    ndx = __row__.length();
    for (int iAux = 0; iAux <= ndx; iAux++)
      receivedChars[iAux] = __row__[iAux];
  }

  while (newData == false)
  { // blocco di lettura

    // controllo della durata della sessione di lettura
    // if (millis() - SessStart > __SesTimeout__) { // blocco di controllo
    //   Serial.print("The session has timed out (");
    //   Serial.print(__SesTimeout__ / 1000);
    //   Serial.println(" seconds)...");
    //   break;
    // } // end of control block

    std::cout << std::flush;

    /* Ciclo di acquisizione della stringa. Si esegue fino a quando non si preme
       return. Ad ogni pressione del tasto si resetta il contatore del timeout.
       Alla pressione del tasto return */
    while (Serial.available())
    { // blocco di acquisizione dei caratteri
      SessStart = millis();
      rc = Serial.read();

      if (rc == endMarker1 || rc == endMarker2)
      {                            // if a CR or LF was received
	receivedChars[ndx] = '\0'; // terminate the character array (string)...
	ndx = 0;
	newData = true;
	// char temp =  Serial.read();
	goto ReturnReceivedString; // return everything
      }
      else if (rc == 127)
      { // A DEL character (decimal 127) was received
	ndx =
	    ndx - 1; // Set the Array-Pointer back to delete the last characte
	Serial.print(
	    rc); // Echo del DEL character back that the Terminal Client app
      }          // removes the last character from the screen
      else
      {
	receivedChars[ndx] = rc; // Receive normal characters..
	ndx++;
	// Serial.print(ndx);
	if (ndx >= numChars)
	{
	  ndx = numChars - 1;
	}

	if (__HideEcho__ ==
	    false)
	{ // Hide echo if user types in a password...
	  Serial.print(rc);
	}
	else
	{ // Normal echo
	  Serial.print("*");
	}
      }

      //

    } // fine del blocco di acquisizione dei caratteri
  }   // fine del blocco di lettura

ReturnReceivedString:

  // copia l'array di input nell'oggetto STRING
  __ROW__.clear();
  for (int iAux = 0; receivedChars[iAux] != '\0'; iAux++)
    __ROW__ += receivedChars[iAux];

  // coversione dell'oggetto String in string
  __row__.clear();
  __row__ = input::STR2str(__ROW__);

} // fine della funzione Ser_Rx()

Link Utili

BLOG Sezione ARI Montecatini Terme

ARI ( Associazione Radioamatori Italiani)

PTLUG ( Linux User Group Pistoia )

ARAL ( Associazione Radiamatori Monte Amiata / Monte Labbro )

Author: ARI people

Created: 2023-11-02 gio 11:08

Validate