NEXTION Display: Serielle Schnittstelle abfragen ohne Library?

Ich habe lange nichts mehr damit gemacht,
aber ich denke ich werde schon ein paar Fragen beantworten können.

Der Kode enthält nichts das AVR spezifisch wäre,
wenn es auf ARM wider Erwarten nicht gehen sollte, kann man das hinbekommen.

Huch, mir raucht der Kopf. Ich habe debug-Serial jetzt auf SerialUSB eingestellt, weil mein board an dem native USB hängt und auch in dem Beispiel-Sketch der Library die entsprechenden Änderungen vorgenommen. Wenn ich auf einen Button auf dem Nextion drücke (der seine ID an die serielle Schnittstelle sendet), bekomme ich am Serial Monitor folgende Ausgabe:

len = 4, strlen = 1
e

Für ein auto-Sleep-Event:

len = 1, strlen = 1

für ein Touch-Event im Sleep mode:

len = 6, strlen = 1
h

und für device automatically wake up:
len = 1, strlen = 1

die Längenangabe len= stimmt mit der zu erwartenden Anzahl an bytes (4 Bei Touch bzw. 6 bei Touch im Sleepmode, sowie 1 bei Sleep-Signalen überein).

die Ausgaben "e" und "h" könnten für die Hex-Werte 0x65 bzw. 0x68 (Touch Event bzw. Touch Event im Sleep mode). Bei den anderen Werten (Sleep und wakeup funktioniert es scheinbar nicht?)
Müsste nicht eigentlich durch den Befehl

SerialUSB.println(buf);

Der gesamte Buffer ausgegeben werden, und nicht nur das erste Zeichen?

Ich möchte nur sicher gehen, ob bei dem einfachen Beispiel noch alles ordnungsgemäß funktioniert bzw. ob ich das auch richtig verstanden habe, ehe ich mich weiter vorwage...

Warum nimmst du nicht die Variante (#5) die den empfangenen Buffer als Dump darstellt?

Entweder durch Verpflanzen des Dumps in das Beispel, oder Erweitern des Dumps durch Teile des Beispiels.

Die Nachrichten vom Nextion enthalten oft \0 Zeichen, dort bricht ein normales print ab,
sobald strlen != len siehst du mit print nicht mehr alles.

Ok, schön langsam komme ich mit der Verarbeitung des Serial-dumps klar.

Ich habe nun einen Test-Sketch, in dem ich ein einfaches Kommando an das Nextion senden möchte, aber leider fehlt mir ein ganzes File:

WhandallOptions16.h: No such file or directory

Ich kann dieses File in deiner Library bzw. auf meinem ganzen Rechner nicht finden. Die Datei scheint aber notwendig zu sein, denn wenn ich die entsprechende include-Anweisung entferne, kommen natürlich andere Errors...

Was macht WhandallOptions16.h genau bzw. wo finde ich die Datei?

Ups, die Abhängikeit hatte ich übersehen, eine zweite existiert auch noch.

Ich habe die Librarys angehängt, die eine ist aber auch klein genug um hier direkt zu stehen.

WhandallOptions16.h

#ifndef WHANDALLOPTIONS16_H
#define WHANDALLOPTIONS16_H
#include <EEPROM.h>
#include <OUtility.h>

#define AF(x) ((__FlashStringHelper *)(x))

typedef const char * const * pmCPTab;

class Options16 {
  protected:
    uint16_t  flags;
    pmCPTab   tabPtr;
 uint16_t eePos;
  public:
    Options16(pmCPTab table, uint16_t eeAdr) : flags(0), tabPtr(table), eePos(eeAdr) {}
    int findTagChar(char tChr);
    bool is(uint16_t opt) {
      return (flags & (1 << opt)) != 0;
    }
    void flip(uint16_t opt) {
      flags ^= (1 << opt);
    }
    void set(uint16_t opt) {
      flags |= (1 << opt);
    }
    void clr(uint16_t opt) {
      flags &= ~(1 << opt);
    }
    void report(uint16_t opt);
    void show();
    void flipReport(uint16_t opt) {
      flip(opt);
      report(opt);
    }
    bool command(char myCmdChar, const char* iLine);
    void fromEEProm() {
      EEPROM.get(eePos, flags);
    }
    void toEEProm() {
      EEPROM.put(eePos, flags);
    }
};

#endif

WhandallOptions16.cpp

#include <WhandallOptions16.h>

const char dWcTail[] PROGMEM = "IRW=|&^]";

void Options16::report(uint16_t opt) {
  uint16_t adr = pgm_read_word(tabPtr + opt);
  pTicks(pgm_read_byte(adr++));
  pBlBefore((char*)adr);
  pBlAround('=');
  Serial.println(is(opt) ? F("ON") : F("OFF"));
}

int Options16::findTagChar(char tChr) {
  char* mPtr;
  for (byte cnt = 0; (mPtr = (char*)pgm_read_word(tabPtr + cnt)) != NULL; cnt++) {
    if (((char)pgm_read_byte(mPtr)) == tChr) {
      return cnt;
    }
  }
  return -1;
}

bool Options16::command(char myCmdChar, const char* iLine) {
  if (*iLine++ != myCmdChar) {
    return false;
  }
  while (isspace(*iLine)) {
    iLine++;
  }
 bool printAll = !*iLine;
 while (*iLine) {
 char curr = *iLine++;
 if (curr == 'R') {
 fromEEProm();
 } else if (curr == 'W') {
 toEEProm();
 } else if (curr == 'I') {
 flags = 0;
 printAll = true;
 } else if (curr == '=') {
 flags = (uint16_t)strtol(iLine, (char**)&iLine, 0);
 printAll = true;
 } else if (curr == '|') {
 flags |= (uint16_t)strtol(iLine, (char**)&iLine, 0);
 printAll = true;
 } else if (curr == '&') {
 flags &= (uint16_t)strtol(iLine, (char**)&iLine, 0);
 printAll = true;
 } else if (curr == '^') {
 flags ^= (uint16_t)strtol(iLine, (char**)&iLine, 0);
 printAll = true;
 } else {
 int val = findTagChar(curr);
 if (val >= 0) {
 flipReport(val);
 } else {
 break;
 }
 }
 }
 if (printAll) {
 pBlAround(myCmdChar);
 show();
 }
  return true;
}

void Options16::show() {
  byte cnt = 0;
  char* mPtr;
  Serial.write('[');
  for (cnt = 0; (mPtr = (char*)pgm_read_word(tabPtr + cnt)) != NULL; cnt++) {
    Serial.write((char)pgm_read_byte(mPtr));
  }
  Serial.println(AF(dWcTail));
  for (byte i = 0; i < cnt; i++) {
    report(i);
  }
}

Die Library verwaltet einzelne benannte Bits in einem 16 Bit Wert.

OUtility hat nur einen Haufen immer wieder auftretender Ausgabeprimitive (mit etwas Dokumentation, deshalb die Größe).

WhandallOptions16.zip (2.13 KB)

OUtility.zip (197 KB)

Danke vielmals:-)
Ich hoffe, ich krieg das hin- ist schon alles ein wenig viel für mich;-)

Jetzt auf jeden Fall mal schöne Weihnachten!

Doch noch eine Frage: die benötigte EEPROM.h ist die Standard Arduino EEPROM Library?

Hahi:
Doch noch eine Frage: die benötigte EEPROM.h ist die Standard Arduino EEPROM Library?

Ja, genau.

Die eingestellten Optionen (16 Stück mit Namen und einem interaktiven Interface über c-strings)
können aus dem EEPROM gelesen und in diesen geschrieben werden.
(Ich zeige dir dazu mal ein Beispiel, aber das muss ich erst vorbereiten).

Ich sagte ja schon, das ist nicht wirklich in dem Zustand dass man es einfach veröffentlichen könnte,
dazu sind noch zu viele Ecken (wie die Abhängigkeiten) vorhanden.

OUtility ist sehr alt und ziemlich 'C', da müsste ich mich noch einmal dransetzen, die Namen sind kryptisch, ...

Die beiden Librarys kannst du ja als BlackBox betrachten.

Die Nextion Library ist durch ihre Blockierungsfreiheit sehr auf Requests, Callbacks und Events ausgelegt,
das ist etwas gewöhnungsbedürftig.

Hm, verstehe. Mit der EEPROM library habe ich Probleme, bzw. mit dem EEPROM an sich. Der SAM-Prozessor hat keinen EEPROM an Bord, ich habe aber einen I2C EEPROM eingbaut, und NEXTION selbst hat auch einen. Aber ich glaube, das sprengt jetzt den Rahmen. Eigentlich brauche ich ja nur die Grundfunktionen deiner Library bzw. möchte diese gerne verstehen. Ist es kompliziert, die herauszufiltern, sodass sie ohne die vielen Zusatzfeatures arbeiten? Ich glaube, ich bin da jetzt etwas überfordert...

Dann müsste es doch so gehen, funktioniert natürlich nicht mehr und macht die Schreib- und Lese-Kommandos sinnlos.

//#include <EEPROM.h>

    void fromEEProm() {
//      EEPROM.get(eePos, flags);
    }
    void toEEProm() {
//      EEPROM.put(eePos, flags);
    }

Ich hoffe, das Christkind war brav??

Jetzt läuft der Compiler weiter, bleibt allerdings bei einem anderen Problem stecken:

Arduino/libraries/WhandallNextion/src/WhandallNextion.cpp: In member function 'bool MsgRetCode::valid()':
/Arduino/libraries/WhandallNextion/src/WhandallNextion.cpp:197:74: error: 'memchr_P' was not declared in this scope
return hasLen(4) && memchr_P(validRetcodes, type, sizeof(validRetcodes));

^
/Arduino/libraries/WhandallNextion/src/WhandallNextion.cpp: In member function 'void NxText::set(float, uint8_t)':
/Arduino/libraries/WhandallNextion/src/WhandallNextion.cpp:1182:52: error: 'dtostrf' was not declared in this scope
set(dtostrf(value, 2 + nachkomma, nachkomma, buff));

^
/Arduino/libraries/WhandallNextion/src/WhandallNextion.cpp: In function 'void NexCommand(const void*)':
/Arduino/libraries/WhandallNextion/src/WhandallNextion.cpp:1287:53: error: 'strncmp_P' was not declared in this scope
uint8_t typ = nxCmd + (strncmp_P(buf, pmsGetBl, 4 ) ? xpRetCode : xpAny);

Ich glaube, ich habe sonst nichts an deinem Code geändert. Hast du eine Idee, woran das liegen könnte?

Bei einem geheimen Programm? Wie sollte ich?

Was meinst du mit "geheimen Programm"? Meinen Sketch? Den kann ich gerne anfügen. Ich dachte eher, dass das Problem irgendwie mit dem Setup der Library zusammenhängt...

Heir mein Test-Sketch:

#include <WhandallSerial.h>  // https://github.com/whandall/WhandallSerial
#include <WhandallNextion.h>
// simple handler just prints some infos about the received line
const char pmsPage0[] PROGMEM = "page 0";
void processLine(const char* buf) {
  SerialUSB.print(F("len = "));
  SerialUSB.print((uint8_t)buf[-1]);
  SerialUSB.print(F(", strlen = "));
  SerialUSB.println(strlen(buf));
  SerialUSB.println(buf);
}

SSerial nextionSerial(Serial1, processLine); // used serial and handler

void setup() {
  while (!SerialUSB) ;
    pinMode(44, OUTPUT);
  digitalWrite( 44, HIGH); //Display-Power
  SerialUSB.begin(250000);
  Serial1.begin(9600);
  nextionSerial.begin(64, optTripleFF); // buffer size and options, maybe +optKeepDlm
 delay(1000);
NexCommand_P(pmsPage0);
  
}

void loop() {
  nextionSerial.loop();    // collect chars and call handler for each line
  
}

Auf deiner Platform scheint es kein PROGMEM zu geben, oder?

Bei mir kompiliert das (für einen Mega) nach Änderung des SerialUSB in Serial.

Das wirst du dann alles selbst ändern müssen, ich kann das nicht testen,
eigentlich sollte es reichen überall die '_P' zu entfernen.

Für den Fehler bezüglich dtostrf brauchst du ein anderes include, k.A. wo das auf deinem System drin ist,
oder auf sprintf ändern.

Auf einem ARM gibt es die PROGMEM Funktionen wohl nicht. Und dtostrf() braucht man da nicht da sprinft() direkt mit Float geht

JA stimmt, PROGMEM gibt es nicht. Ich glaube, da ist ziemlich viel von deinem Code von zu erledigenden Änderungen betroffen, oder?

Hallo,

der ARM sollte doch eine Unmenge an RAM haben. Dann eben ohne PROGMEM und RAM zuballern. :slight_smile:

Hahi:
Ich glaube, da ist ziemlich viel von deinem Code von zu erledigenden Änderungen betroffen, oder?

Whandall:
... eigentlich sollte es reichen überall die '_P' zu entfernen.

Ich bin nicht sicher, wo ich überall '_P' entfernen soll. Nur bei den Variablen-Namen, oder auch bei den Funktionen? Auch in OUtility? Da gibt es beispielsweise die Funktion:

void pwp_P(const char *pPtr, const char aChar) {
  pPS(pPtr);
  Serial.write(aChar);
}

Ausserdem müsste ich auch bei sämtlichen Variablen-Definitionen das "PROGMEM" rausnehmen, oder?

In der Nextion.h ist mir folgendes aufgefallen: Es gibt zwei Funktionen, eine zum Senden des "normalen" buf, und eine für den Buffer aus dem PROGMEM:

void NexCommand(const void* vBuf);
/*!	\brief Send a command to the display, selectable print
 *
 *	No check for length is performed, as the data comes from PROGMEM.
 *
 *	@param [in] pmvBuf string in PROGMEM
 */
void NexCommand_P(const void* pmvBuf);
/**

Wenn ich einfach bei "NexCommand_P" das "_P" weggebe, wird die Funktion aber immer noch nach "pmvBuf" statt "vBuf" verlangen. Für mich sieht es so aus, als müsste ich da schon mehr ändern als nur "_P" wegzulassen. Ich mache gerne alle Änderungen, aber ich befürchte, dass sich da sehr schnell Fehler einschleichen können - für dich wäre das wahrscheinlich kein Problem, weil der Code ja von dir ist, aber ich hab da zu viel Respekt, dass ich dann möglicherweise einen ziemlich buggy code zusammenbastle.
Noch gebe ich aber nicht auf;-) Wenn du mir glaubhaft machen kannst, dass das alles halb so wild ist, versuche ich mich gerne - kannst du bitte nochmal einen detaillierteren Blick auf deinen ganzen Code werfen und mir dann sagen, ob das wirklich einfach hinzubekommen ist? ich meine jetzt nicht, dass du das für mich umschreiben sollst - aber vielleicht kannst du mir ganz genau sagen, wo ich überall etwas ändern muss? DANKE!

Mach die _P da weg wo der Compiler sie anmault.

Hahi:
In der Nextion.h ist mir folgendes aufgefallen: Es gibt zwei Funktionen, eine zum Senden des "normalen" buf, und eine für den Buffer aus dem PROGMEM:

Wenn es keinen Unterschied zwischen RAM und Flash gibt sind, werden manche Funktionen überflüssig,
das ist ein Beispiel dafür.

Hahi:
kannst du bitte nochmal einen detaillierteren Blick auf deinen ganzen Code werfen und mir dann sagen, ob das wirklich einfach hinzubekommen ist?

Ich denke schon dass das einfach hinzubekommen ist.

Hahi:
ich meine jetzt nicht, dass du das für mich umschreiben sollst - aber vielleicht kannst du mir ganz genau sagen, wo ich überall etwas ändern muss?

Wenn du diese beiden Dinge betrachtest, stellst du dann nicht fest, dass beides das Gleiche wäre?
Im zweiten Fall müsste ich es dir nur noch zusätzlich erklären.

Nimm Notepad++ zum Editieren, da kannst du in allen beteiligten Dateien gleichzeitig suchen und ändern.