Enhanced Serial Monitor - ESM4 new error reporting system

Here is the supplied sample .INO

char * sSketch = "ESMexample.ino";

#include "_esm4.h"

char    sESMbuffer[50];
char *  psESMname  = "";
char *  psESMvalue = "";

#define mBLINK  1
#define mDRAW   2
#define mHIST   3
#define mIMU    4
#define mLCD    5
#define mLOG    6
#define mSTOP   7
#define mSWP    8
#define mXY     9

int iInterval = 500;
int iMode;
long lCount = 0;

float fPitch = 0.0;
float fRoll  = 0.0;

char sTime[8];
long lTime;
long lHr;
long lMin;
long lSec;
long lLastHr  = -1;
long lLastMin = -1;
long lLastSec = -1;

char * sResetMsg = "#esm~run~demo\\ESMresetDemo.script.txt";
//--------------------------------------------------------------------------------------
void setup() { //FN
  pinMode(LED_BUILTIN, OUTPUT);

  ESMbegin(250000);
  ESM("#esm~title~%s", sSketch);
  ESM("#log~Demo sketch started");
  ESM("#data~set~baud~{BAUD}");
  ESM("#data~set~port~{PORT}");
  ESM(sResetMsg);

  iMode = mSTOP;

  return;
}
//--------------------------------------------------------------------------------------
void loop() { //FN
  static long lM = millis();

  vReadSerial();

  if (millis() - lM > iInterval) {
    lM = millis();
    lCount++;
    if (lCount > 1000) lCount = 0;

    switch (iMode) {
      case mIMU:   doIMU();    break;
      case mBLINK: doBLINK();  break;
      case mDRAW:  doDRAW();   break;
      case mHIST:  doHIST();   break;
      case mLCD:   doLCD();    break;
      case mLOG:   doLOG();    break;
      case mSTOP:              break;
      case mSWP:   doSWP();    break;
      case mXY:    doXY();     break;
    }
  }
}
//--------------------------------------------------------------------------------------
void doBLINK() { // FN
  static bool bOn = true;

  if (bOn) digitalWrite(LED_BUILTIN, HIGH);
  else     digitalWrite(LED_BUILTIN, LOW);

  ESM("#log~Blink:%s", bOn ? "on": "off");
  bOn = bOn ? false : true;
}
//--------------------------------------------------------------------------------------
void vCalcTime() { //FN
  long lNow;

  lNow = lTime + int(millis()/1000);
  lSec = lNow%60;
  lNow /= 60;
  lMin = lNow%60;
  lNow /= 60;
  lHr  = lNow%60;
}
//--------------------------------------------------------------------------------------
void doDRAW() { // FN
  static int iRot = 0;
  static long lM = millis();

  if (millis() - lM >= 1000) {
    lM = millis();
    ESM("#draw~frectangle~1~360~200~75~20");
    //ESM("#draw~text~0~365~210~{TIME}");
    ESM("#draw~text~0~365~210~%d:%d:%d", (int)lHr, (int)lMin, (int)lSec);
  }

  vCalcTime();
  lHr = lHr%12;
  if (lLastHr != lHr) {
    if (lHr == 0) {
      ESM("draw~fellipse~6~400~100~102~102");
    }
    else {
      ESM("#draw~fpie~3~400~100~100~100~0~%s", ESM0(lHr * 30));
    }
    lLastHr = lHr;
  }
  if (lLastMin != lMin) {
    if (lMin == 0) {
      ESM("draw~fellipse~6~400~100~102~102");
      ESM("#draw~fpie~3~400~100~100~100~0~%s", ESM0(lHr * 30));
    }
    else {
      ESM("#draw~fpie~4~400~100~80~80~0~%s", ESM0(lMin * 6));
    }
    lLastMin = lMin;
  }
  if (lLastSec != lSec) {
    lLastSec = lSec;
    if (lSec == 0) {
      ESM("#draw~fellipse~6~400~100~102~102");
      ESM("#draw~fpie~3~400~100~100~100~0~%s", ESM0(lHr * 30));
      ESM("#draw~fpie~4~400~100~80~80~0~%s", ESM0(lMin * 6));
      lLastHr = lLastMin = -1;
    }
    else {
      ESM("#draw~fpie~2~400~100~60~60~0~%s", ESM0(lSec * 6));
    }
  }

  iRot += 6;
  if (iRot > 360) {
    iRot = 0;
    ESM("#draw~fellipse~6~400~180~32~32");
  }
  else {
    ESM("#draw~fpie~1~400~180~30~30~0~%d", iRot);
  }

  ESM("#draw~fellipse~%s~%d~%d~%d~%d",
    ESM0(lCount), int(random(350, 451)), int(random(350, 451)), int(random(5, 30)), int(random(5, 30)));
}
//--------------------------------------------------------------------------------------
void doHIST() { //FN
  float fValue = float(random(-1100, 1200)/100.0);
  ESM("#hist~%s", ESM2(fValue));

  fValue = float(random(-18, 18)/10.0);
  ESM("#hist~%s", ESM2(fValue));
}
//--------------------------------------------------------------------------------------
void doIMU() { // FN
  fPitch = fPitch + float(random(-20, 20)/10.0);
  fRoll  = fRoll  + float(random(-20, 20)/10.0);

  ESM("#imu~%s~%s", ESM1(fPitch), ESM1(fRoll));

  if (lCount%100 == 0) {
    fPitch = fRoll = 0.0;
    ESM("#imu~reset");
  }
}
//--------------------------------------------------------------------------------------
void doLCD() { //FN
  ESM("#lcd~1~45~{NOW} {PORT} @ {BAUD}");
  ESM("#lcd~2~45~Interval = %d mS   ~{BLUE}~{WHITE}", iInterval);
  ESM("#lcd~%d~%d~ ~%d~%d", int(random(15, 21)), int(random(65, 76)), int(lCount), int(lCount));
}
//--------------------------------------------------------------------------------------
void doLOG() { //FN
  ESM("#log~Logged at {TIME}");
}
//--------------------------------------------------------------------------------------
void doSWP() { // FN
  static float fSmooth = 0.0;
  float f = float(random(0, 5000)/100000.0);

  fSmooth = (f + (9.0 * fSmooth))/10.0;

  ESM("#swp~%s~%s~%s~%s~%s",
    ESM3(float(random(20000, 30000)/1000.0)),
    ESM3(float(random(20000, 30000)/10.0)),
    ESM4(f),
    ESM4(fSmooth),
    ESMf2s(f, 6));
}
//--------------------------------------------------------------------------------------
void doXY() { // FN
  ESM("#xy~%d~%d~%d", int(lCount), int(random(0, 501)), int(random(0, 501)));
}
//--------------------------------------------------------------------------------------
#define CMD(x)   strcmp(x, psESMname)  == 0
#define VALUE(x) strcmp(x, psESMvalue) == 0

void vReadSerial() { //FN
  int iParamCount = ESMread(sESMbuffer, sizeof(sESMbuffer));

  if (iParamCount) {
    //ESM("#log~Params:%d", iParamCount);
    //for (int n = 0; n < iParamCount; n++) {
    //  ESM("#log~Param%d:%s", n, ESMparam(sESMbuffer, n));
    //}
  }
  else {
    return;
  }

  psESMname  = ESMparam(sESMbuffer, 0); ESMupper(psESMname);
  psESMvalue = ESMparam(sESMbuffer, 1); ESMupper(psESMvalue);

  ESM("#data~set~cmd~%s", psESMname);
  ESM("#data~set~millis~%s", ESM0(millis()));

  if (CMD("STOP")) {
    iMode = mSTOP;
  }

  else if (CMD("TIME")) {
    strcpy(sTime, psESMvalue);
    ESM("#log~time received %s", sTime);

    sTime[2] = 0;
    sTime[5] = 0;
    lHr  = atoi(&sTime[0]);
    lMin = atoi(&sTime[3]);
    lSec = atoi(&sTime[6]);

    lTime = (3600 * lHr) + (60 * lMin) + lSec - int(millis()/1000);
  }

  else if (CMD("INT")) {
    iInterval = constrain(atoi(psESMvalue), 1, 2500);
    ESM("#log~Interval = %d mS", iInterval);
  }

  else if (CMD("RESTART")) {
    ESM(sResetMsg);
    delay(1000);
    asm volatile(" jmp 0");
  }

  else if (CMD("CLOSE")) {
    ESM(sResetMsg);
    ESM("#esm~close");
    delay(1000);
  }

  else if (CMD("REOPEN")) {
    ESM(sResetMsg);
    ESM("#esm~reopen");
    delay(1000);
  }

  else if (CMD("BLINK")) {
    iMode = mBLINK;
    ESM("#log~Blink every %d mS on pin %d",
    iInterval, LED_BUILTIN);
  }

  else if (CMD("DRAW")) {
    iMode = mDRAW;
    lLastHr = lLastMin = lLastSec = -1;
    ESM("#esm~run~demo\\ESMdrawDemo.script.txt");
  }

  else if (CMD("HIST")) {
    iMode = mHIST;
    ESM("#esm~run~demo\\ESMhistDemo.script.txt");
  }

  else if (CMD("IMU")) {
    iMode = mIMU;
    ESM("#esm~run~demo\\ESMimuDemo.script.txt");
    fPitch = fRoll = 0.0;
  }

  else if (CMD("LCD")) {
    iMode = mLCD;
    ESM("#esm~run~demo\\ESMlcdDemo.script.txt");
  }

  else if (CMD("LOG")) {
    iMode = mLOG;
    ESM(sResetMsg);
  }

  else if (CMD("SWP")) {
    iMode = mSWP;
    ESM("#esm~run~demo\\ESMswpDemo.script.txt");
  }

  else if (CMD("XY")) {
    iMode = mXY;
    ESM("#esm~run~demo\\ESMxyDemo.script.txt");
  }

  else if (CMD("OUTPUT")) {
    if (VALUE("ON"))        ESMoutput(true);
    else if (VALUE("OFF"))  ESMoutput(false);
  }

  ESM("#data~set~int~%s", ESM0(iInterval));

  int iModeOutput;
  iModeOutput = ESMoutput();
  ESMoutput(true);
  ESM("#data~set~output~%s", iModeOutput ? "ON" : "OFF");
  ESMoutput(iModeOutput);

  ESM("#log~%s @ %s", psESMname, "{TIME}");
}
//--------------------------------------------------------------------------------------

The support header file _esm4.h

/*
Support file for ESM4
*/

#ifndef _esm4_h
#define _esm4_h

#include "Arduino.h"

// colour codes used in the ESM(...) messages
#define penBlack  0
#define penRed    1
#define penBlue   2
#define penGreen  3
#define penOrange 4
#define penGray   5
#define penWhite  6

#define ESM_PRINTBUFFER 80
// A buffer for storing a message string prior to sending to the ESM

#define ESM_CONVERTBUFFERS 10
// The number of buffers used in the number to string conversion
// function ESMf2s(...). This is the number of calls to ESMf2s or
// its # defines in one call to ESM(...)

char *  ESM(char *sFmt, ...);
// The main function for sending messages to the ESM
// it is like sprintf and this would be a good source of
// information on how to create the format string sFmt
// and the variable parameter passing using ...
// NOTE variable arguments support id currently limited
// by the compiler used by the Arduino IDE. It is safe to
// use %d and %s. Other formating strings you need to experiment
// with. Use ESMf2s to convert any numeric into a string and is
// about the only way to conveniently handle float variables'
// It returns a pointer to the internal message buffer

void    ESMbegin(long lBaudRate);
// initilaise the COM port. It also sets up printing/sending
// to the COM port properly

int     ESMread(char acDest[], int iLen);
// Checks to see if there is anything in the Serial port
// and if it matches the ESM protocol. It returns the number
// parameters in a message begining with "@" or zero if it
// is not recognised as a valid message

char *  ESMparam(char *pBuff, int iParam);
// This extracts the parameters, as separated by the "~" character
// bBuff is the address of the message buffer and iParam is the nth
// parameter with 0 being the first one

char *  ESMupper(char *pStr);
// This is a helper function to convert a string to upper case

char *  ESMf2s(float fValue, int iPrecision);
// This is the helper function for converting numeric values into a string.
// The function manages ESM_CONVERTBUFFERS
// fValue can be a float, int, long, boolean
// iPrecision is the number of digits after the decimal point
// iPrecision = -1 will convert to a binary representation
// between 0000 0000 and 1111 1111
// It returns a pinter to the internal buffer containing the
// string representation

// helper/convenience macros for ESMf2s
#define ESMs ESMf2s           // general purpose conversion of numbers to string
#define ESMb(x) ESMs(x, -1)   // converts number to string binary
#define ESM0(x) ESMs(x, 0)    // convert to integer
#define ESM1(x) ESMs(x, 1)    // convert to 1 decimal place
#define ESM2(x) ESMs(x, 2)    // convert to 2 decimal places
#define ESM3(x) ESMs(x, 3)    // convert to 3 decimal places
#define ESM4(x) ESMs(x, 4)    // convert to 4 decimal places
#define ESM5(x) ESMs(x, 5)    // convert to 5 decimal places

int    ESMoutput(int iMode = -1);
// This function switches putput from the Arduino back to the ESM on or off
// iMode = true switches it on
// iMode = false
// iMode = -1 or left blank returns the state of the output flag
// It always returns the current state of the output flag

#endif // _esm4_h

and library code _esm4.cpp

/*
Support library for Enhanced Serial Monitor ESM4
*/

#include "_esm4.h"

char   ESM_BUFFER[ESM_PRINTBUFFER];

//--------------------------------------------------------------------------------------
int   ESMoutput(int iMode) { //FN
  static int iOutput = true;

  if (iMode == -1) {
    return iOutput;
  }

  iOutput = iMode;

  return iOutput;
}
//--------------------------------------------------------------------------------------
char * ESM(char *sFmt, ...) { //FN

  if (ESMoutput() == false) return "";

  memset(ESM_BUFFER, 0, sizeof(ESM_BUFFER));
  va_list args;
  va_start(args, sFmt);
  vsprintf(ESM_BUFFER, sFmt, args);
  va_end(args);

  //printf("%s$%d\n", ESM_BUFFER, strlen(ESM_BUFFER));  // ESM v3
  printf("%s\n", ESM_BUFFER);                           // ESM v4

  return ESM_BUFFER;
}
//--------------------------------------------------------------------------------------
char * ESMf2s(float f, int p) { //FN

  if (ESMoutput() == false) return "";

  char * pBuff;                               // use to remember which part of the buffer to use for dtostrf
  static char sBuff[ESM_CONVERTBUFFERS][10];  // space for characters including NULL terminator for each float
  static int iCount = 0;                      // keep a tab of next place in sBuff to use
  pBuff = sBuff[iCount];                      // use this buffer
  if (iCount >= ESM_CONVERTBUFFERS - 1) {     // check for wrap
    iCount = 0;                               // if wrapping start again and reset
  }
  else {
    iCount++;                                 // advance the counter
  }

  if (p == -1) { // 1 byte binary display, 0 - 255 then wraps
    long l = f;
    Serial.println(l);
    pBuff[0] = (l & 0x80 ? '1' : '0');
    pBuff[1] = (l & 0x40 ? '1' : '0');
    pBuff[2] = (l & 0x20 ? '1' : '0');
    pBuff[3] = (l & 0x10 ? '1' : '0');
    pBuff[4] = ' ';
    pBuff[5] = (l & 0x08 ? '1' : '0');
    pBuff[6] = (l & 0x04 ? '1' : '0');
    pBuff[7] = (l & 0x02 ? '1' : '0');
    pBuff[8] = (l & 0x01 ? '1' : '0');
    pBuff[9] = 0;
    return pBuff;
  }
  else {
    return dtostrf(f, 0, p, pBuff);       // call the library function
  }
}
//--------------------------------------------------------------------------------------
int _putc(char c, FILE *) { //FN
  Serial.write(c);
  return c;
}
//-------------------------------------------------------------------------------------------
void ESMbegin(long lBaudRate) { //FN
  Serial.begin(lBaudRate);
  fdevopen(&_putc, 0);
}
//--------------------------------------------------------------------------------------
int ESMread(char acDest[], int iLen) { //FN
  acDest[0] = 0;
  if (Serial.available()) {
    //if (Serial.peek() == '#') { //ESM v3
    if (Serial.peek() == '@') { // ESM v4
      delay(10); // ! seems to make reading more reliable. may be worth tuning
      Serial.read();
      int n = 1;
      memset(acDest, 0 , iLen);
      acDest[0] = 1;
      while (n < iLen -1) {
        delay(1);  // ! seems to make reading more reliable. may be worth tuning
        if (Serial.available()) {
          char c = Serial.read();
          if (c == '~') {
            c = 0;
            acDest[0] = acDest[0] + 1;
          }
          acDest[n++] = c;
        }
        else {
          acDest[n] = 0;
          return acDest[0];
        }
      }
    }
    else
      Serial.read();
  }
  return acDest[0];
}
//--------------------------------------------------------------------------------------
char * ESMparam(char *pBuff, int iParam) { //FN
  if (iParam > *pBuff) return NULL;

  pBuff++;

  while (iParam-- > 0) {
    while (*pBuff++ != 0);
  }
  return pBuff;
}
//--------------------------------------------------------------------------------------
char * ESMupper(char *pStr) { //FN
    char *pStart = pStr;

    while(*pStr) {
        *pStr = toupper(*pStr);
        *pStr++;
    }
    return pStart;
}
//------------------------------------------------------------------------------------

And this is what a smart help file, as seen on the screen dump, looks like:-

Once the sketch |#esm~start~..\examples\ESMexample\ESMexample.ino| has been uploaded to the Arduino the following messages:-
|@log| |@draw| |@hist| |@imu| |@lcd| |@swp| |@xy| |@blink| |@stop|
demonstrate the visualisers by sending simulated data to the PC.
|@output~on| |@output~off| Switches serial output on/off to the PC.
════════════════════════════════════════════════
The COM port on the Arduino is expecting to be opened at 250000 baud.
|#esm~open~{port}~{baud}| |#esm~close| |#esm~reopen~{port}~{baud}|
|#esm~clear| |#esm~copy|
════════════════════════════════════════════════
|@int~1| |@int~2| |@int~5| |@int~10| |@int~50| |@int~100| |@int~200| |@int~500|
|#data~set~n~999| |#data~set~n~888| |@int~{{n}}|
Set the interval in milliseconds that the demos 'tick' at. Changing the interval is useful way to establish the maximum speed at which messages can be sent to the ESM - this depends on the performance of your PC. Watch the output buffer size on the ESM form does not continually increase - if it does the data rate is too high or too much display work is being done (try pausing the ESM output).
|#esm~pause~on| |#esm~pause~off| |#esm~log~on| |#esm~log~off|
════════════════════════════════════════════════
This link will open this file in a text editor |#esm~start~demo\ESMdemo.help.txt|. It has been intentionally written to

And a script file

#draw~hide
#hist~hide
#imu~hide
#lcd~hide
#swp~hide
#xy~hide
#esm~show
#log~show
#data~show
#help~show
#help~open~demo\ESMdemo.help.txt

But you don't need to use script or help files to use ESM4. Simple write your sketch with the ESM(...) functions calls and open the visualisers manually.

The full list of messages can be found below:-

The forms and visualisers will process the following standard messages:- 

(Replace #XXX with the appropriate form/visualiser name. #ESM, #HELP, #LOG, #DATA, #DRAW, #HIST, #IMU, #LCD, #SWP, #XY) 

#XXX~SHOW - shows the form or visualiser 
#XXX~HIDE - hides the the form or visualiser 
#XXX~MOVE~xpos~ypos~width~height - moves and/or resizes the form or visualiser. Leaving xpos, ypos, width or height blank will maintain the existing value of that parameter. Setting width and height beyond their maximum values will cause the form to be sized to its allowable maximum. Setting the width and height to less than their minimum values will cause the form to be resized to its allowable minimum. 

Some also support:- 
#XXX~LOG~OFF - stops echoing messages to the LOG 
#XXX~LOG~ON - starts echoing messages to the LOG 
#XXX~PAUSE~OFF - messages do not update the form or visualiser 
#XXX~PAUSE~ON - messages update the form or visualiser 


--------------------------------------------------------------------------------
#DATA~CLEAR - removes all entries from the name/value database 
#DATA~RELOAD - reloads the database from the file ESMdata.txt 
#DATA~SEND~name - sends data associated with the 'name' as stored in the name/value database to the Arduino 
#DATA~SET~name~value - sets or adds the "name" into the name/value database with "value" 
--------------------------------------------------------------------------------
#DRAW~ARC~color~x~y~w~h~start~sweep - an arc is drawn centered on x, y or width and height, "w" and "h", starting at "start" degrees and sweeping for "sweep" degrees 
#DRAW~CLEAR - the drawing area is cleared to white 
#DRAW~CROSS~color~x~y - a cross is drawn at the location x, y 
#DRAW~ELLIPSE~color~x~y~w~h - an ellipse is drawn centred on x, y of width "w" and height "h" 
#DRAW~FELLIPSE~color~x~y~w~h - as ellispe but filled 
#DRAW~FPIE~color~x~y~w~h~start~sweep - as pie but filled 
#DRAW~FRECTANGLE~color~x~y~w~h - as rectangle but filled 
#DRAW~LINE~color~x0~y0~x1~y1 - line is drawn betweem x0, y0 and x1, y1 
#DRAW~PIE~color~x~y~w~h~start~sweep - as arc but as a pie 
#DRAW~RECTANGLE~color~x~y~w~h - a rectangle is drawn from x, y of width "w" and height "h" 
#DRAW~TEXT~color~x~y~text~font~angle - "text" is drawn at x, y using "font" size and at "angle" degress 
--------------------------------------------------------------------------------
#ESM~ADDMSG~message - "message" is added to the send field dropdown. 
#ESM~ARRANGE - sets the forms and visualisers back to their default positions 
#ESM~BEEP - sounds a beep on the PC if the speaker is on 
#ESM~CLEAR - clears the message history 
#ESM~CLEARMSG - clears the message in the send field 
#ESM~CLEARMSGLIST - clears the messages in the send field dropdown 
#ESM~CLOSE - closes the port if it is open 
#ESM~COPY - writes the message history to ESMcopy.txt and shows it in the HELP form 
#ESM~DELAY~period - used in a script to give a "period" seconds delay before executing the next instruction 
#ESM~HIDEALL - hides all the forms and visualisers 
#ESM~MAXIMISE - maximises the main window 
#ESM~MINIMISE - minimises the main window 
#ESM~OPEN~comport~baud - opens the "comport" at "baud" rate 
#ESM~REOPEN~comport~baud - closes and reopens the "comport" at "baud" rate 
#ESM~RESTORE - restores the main window to its previously non-maximised position and size 
#ESM~RUN~scriptfile - processes the "scriptfile" 
#ESM~SETMSG~message - "message" set into the send field 
#ESM~SHELL~externalprogram - opens the "externalprogram". Also try START 
#ESM~SHOWALL - opens all forms and visualisers 
#ESM~START~externalprogram - opens the "externalprogram". Also try SHELL 
--------------------------------------------------------------------------------
#HELP~CLEAR - clears the HELP form 
#HELP~HOME~message - sets the "message" to be applied when the home button is pressed 
#HELP~OPEN~file - opens and pre-processes if required, the "file" and shows it in the form 
--------------------------------------------------------------------------------
#HIST~value - adds the "value" to the appropriate histogram bar 
#HIST~INT~value - sets the interva between bars to "value" 
#HIST~MIN~value - sets the minumum value of the first histogram bar 
#HIST~RESET - sets the histogram bars to zero 
--------------------------------------------------------------------------------
#IMU~pitch~roll - updates the visualiser with "pitch" and "roll" 
#IMU~INVERT - cause the display to invert the incoming data 
#IMU~RESET - sets the pitch and roll back to zero 
--------------------------------------------------------------------------------
#LCD~row~col~text~forecolour~backcolour - writes the "text" at "row", "col" using "forecolour" and "backcolour" 
#LCD~CLEAR - clears the visualiser to black 
#LCD~SCROLL - moves the content of the visualiser up one row 
--------------------------------------------------------------------------------
#LOG~text - displays the "text" in the form and outputs to a file if open 
#LOG~CLEAR - clears the listing 
#LOG~CLOSE - closes any open log file 
#LOG~COPY - writes the message history to ESMcopy.txt and shows it in the HELP form 
#LOG~ERASE - deletes the contents of the currently open log file 
#LOG~OPEN~file - opens and /or creates the specified log "file" 
#LOG~WRAP~OFF - causes long text to wrap in the form 
#LOG~WRAP~ON - causes long text to not wrap in the form 
--------------------------------------------------------------------------------
#SWP~AUTO - resets the y minimum and/or y range to accomdate the incoming data 
#SWP~BLACK~OFF~text~gain~offset - switches off showing the balck channel, the name of it is set to "text", the "gain" and "offset" to be applied to the incoming data before display 
#SWP~BLACK~ON~text~gain~offset - as above but the output is switched on 
#SWP~BLUE - see #SWP~BLACK 
#SWP~CLEAR - clears the visualiser to white and sets the offset to zero 
#SWP~GREEN - see #SWP~BLACK 
#SWP~ORANGE - see #SWP~BLACK 
#SWP~POINTS~OFF - data points are not shown with a cross 
#SWP~POINTS~ON - data points are shown with a cross 
#SWP~RED - see #SWP~BLACK 
#SWP~RESET - sets the offset to zero, the visialiser is not set to white 
#SWP~SIZE~FULL - sets the visualiser to 1000 pixels wide 
#SWP~SIZE~500 - sets the visualiser to 500 pixels wide 
#SWP~TICKS~0 - switches off the tick marker 
#SWP~TICKS~10M - displays a vertical line on the next message after a 10 minute interval 
#SWP~TICKS~10S - displays a vertical line on the next message after a 10 second interval 
#SWP~TICKS~1H - displays a vertical line on the next message after a 1 hour interval 
#SWP~TICKS~1M - displays a vertical line on the next message after a 1 minute interval 
#SWP~TICKS~1S - displays a vertical line on the next message after a 1 second interval 
#SWP~XPOINTS~value - sets the number of data points that will be plotted on the x axis 
#SWP~YINT~value - sets the y axis interval to "value" 
#SWP~YMIN~value - sets the y axis minumum to "value" 
--------------------------------------------------------------------------------
#XY~BLACK~text - sets the title of the black channel to "text" 
#XY~BLUE~text - see #XY~BLACK 
#XY~CLEAR - clears the visualiser to white 
#XY~GREEN~text - see #XY~BLACK 
#XY~ORANGE~text - see #XY~BLACK 
#XY~RED~text - see #XY~BLACK 
#XY~XINT~value - sets the x axis interval to "value" 
#XY~XMIN~value - sets the x axis minimu to "value" 
#XY~YINT - sets the y axis interval to "value" 
#XY~YMIN~value - sets the y axis minimu to "value"

Update 4.0.0.1. See first posting for download link

  • Minimise button added to main form
  • Open button now easier to select port
  • Colour change for connection and buffer info
  • Modified to handle blurry fonts (much reported issue with MS applications) running on large screen resolutions (please feedback if you are using a screen with a very large pixel resoltion)

Whoops... missed the message of how to plot a point on the XY visualiser off the help. So here it is:-

#XY~colour~x~y - plots the point at x, y in "colour"

Mea Culpa

Alan

New feature idea.

Allow multiple 'databases' so each project can then have its own database.

Version 4.0.0.2

Port opening doesn't refresh com port list automatically. Now remembers last port.

Slightly faster serial reading and processing

Version 4.0.0.3 released. There a few improvements but the main reason is that this version shows how to do a wireless/remote ESM serial monitor.

This is provided by equipping two Arduinos with NRF24L01+ devices to do the communicating. It is all done in the supplied sketch and this could be used as a skeleton for other communications technologies.

All very simply done by extending the message protocol to include "@@" and "@#" to direct the message across the NRF connection.

A smart help user interface makes it easy to try out the remote serial monitor features.

Cheers Alan

NRF library now added to ZIP file

Catch22? Not quite. Wireless serial monitor... you don't need to build the Arduinos with the NRFs in order see how to build the Arduinos with the NRFs...

If you want to find out about the wireless serial monitor using NRF24L01+ you can just open the smart help file from the message sending part of the main ESM form using #help~open~_wireless\help.txt. This will be a smart help link on the main help page in the next release for added convenience :slight_smile:

You do need to have at least version 4.0.0.3 which has the wireless support of course!

I have added an example of how to check if a serial port is connected and open with an Arduino. From the example help file...

Echo demonstration

This shows a method by which the Arduino can determine if it is connnected to a serial port.

One technique is to send the Arduino a message from the IDE serial monitor. However, this also requires a person to be "attached" to the IDE to make this work and it is not so easy to ensure when, if at all, the message gets sent.

The approach with ESM4 is to have the Arduino send a message back to back to the ESM which it will then respond by sending a message back to the Arduino. If the message isn't received then it isn't connected.

Download version 4.0.0.4 from the first posting.

Also returned the vSerialRead function to its previous state where it didn't need to process the serial input in two different ways depending on whether you wanted support for a wireless or not wireless connection to ESM4. The parsing of the input string is now moved to _esp.cpp library function.

Cheers Ala.

I've been working on customised visualisers/scripts for a little while for very specific applications (which only pop up if the correct messages are sent to the ESM so don't expect to see any new forms unless you are involved in these projects).

I am now back on the project so if there are features that anyone thinks would be of general interest please let me know and I will add them to my list for consideration.

Also if there is something very specific to your project please also consider getting in touch with me. I may be able to help.

Alan

ESM version 4.0.2.0 is now available for download from http://alanboother.co.uk/project-cafe/esm4/_ESM4.0.2.0{97F83AC2}.zip

The big change in this release is the introduction of “Projects” and a few minor changes and a bug fix or two.

A Project in ESM terms is a regularised way to write sketches, scripts, help files and reset files. The ESM will write a complete running system, including the sketch file which will compile and run without modification. This makes it easy to get started, see how to use the features of the ESM. All these files can all be modified to suit your particular project. You don’t have to use the project approach and you can still just open up the ESM and use it as a smart serial monitor. Generated files come from templates which you can also modify to be more suitable to your own style.

The basic generated sketch shows how to communicate from ESM to Arduino and from Arduino to ESM, update DATA on the ESM and use it next time the Arduino sketch starts, switch the serial output on and off, automatically refresh data in the help screen which can also be used to update messages back to the Arduino…

The help files are a really convenient way to add in project support information either for end users or during development.

Each project now has its own independent DATA.

Smaller changes to the XY plot visualiser include support for the drawing commands found in the DRAW visualiser (LINE, PIE, TEXT etc) and a position cursor.

The SWP visualiser now records the data that appears in the view and may be replayed after you have adjusted the y axis scales and offsets. Useful in case you missed something important because you hadn’t set the axis to the best values before capturing the data.

The main help file has been rewritten.

The folder structure has been cleaned up and so it is recommended that a clean installation into the Arduino libraries folder is carried out and then any files you may have created copied back into it.

A really convenient tweak in this release is the automatic sending of messages indicating the COM port is opened or is closing. This allows you write your sketch to perform differently whether its connected to serial input/output or not – should that be important to you.

Cheers
Alan

25th June 2018

ESM version 4.0.3.0 now available for download from http://alanboother.co.uk/project-cafe/esm4/_ESM4.0.3.0{E29BA8E2}.zip

THE big improvement this release is error reporting! When the ESM fails to recognise or process a message the error is reported in the main monitor form along with some information as to why it may be wrong. Also used when trying to send messages to the Arduino when the COM port isn't open. The display turns to red text when an error is noticed and a red button shows on the form making it hard to miss. Pressing the button clears the text back to default colour.

Also the directory structure has been simplified so it would be best to install this version afresh and then copy any of your own files back in.

When the ESM starts this is now a project which further simplifies the use of the ESM.

Also a couple of minor bug fixes.

I recommend you unzip the file into your Arduino library folder ersulting in a folder called _ESM4.0.0.3.0

Hello Alan,

I have been using ESM v3 successfully for several years and just now decided to try upgrading to v4.0.3.0. I like the enhancements, especially the Project concept and the ability to put setup commands in the reset.txt file.

I wrote a simple sketch to try it out and observed a couple of issues.

-- In the reset.txt file, trying to set the Histogram interval (which I assume is the bin size) to 10, I was not able to get it to accept

#hist~int~10

or any variation on that, including upper case and other values. It gives me the error

[ERR]#hist~int~10
[EX]Check message parametersIndex was outside the bounds of the array.

-- I see that you now have a mechanism with @PORTopened and @PORTclosing to tell the sketch to stop sending data if the port is closed. I noticed that if I do not use that and just close the port so the sketch is continuing to try to send data, the ESM hangs when I re-open the port. Perhaps a buffer overflows if there is a lot of data waiting when you open the port. I have to kill ESM in the Task Manager and restart it to recover.

I am using a 32u4 based Arduino with its integrated USB controller in case that matters. A simple way to get the sketch to stop sending serial data for these processors is to use the undocumented Serial.dtr(), which returns true if the serial port is open and false otherwise.

Thanks for all your efforts on this.

JimHarman:

I've just tried the #hist~int~10 (and other values) setting and not getting this problem. Does this problem happen if you send the message directly from the on-screen message sending entry field?

I will send you a link to the latest .exe in case it was a bug that was fixed but has yet to be released. Please let me know.

The port control messages are no more than ordinary messages to the Arduino and only have the meaning that you can see in the message handler vDoMsg(). I'm not expecting an issue here but, hey ho, stuff happens. I would expect the Arduino to not send data if the port wasn't connected irrespective of whether there is an unconnected ESM somewhere in the mix.

Try renaming these messages in vDoMsg() so they don't get invoked and let me know if it clears the problem. Also how much data is collecting in the port? Have a look at the number on the title bar of the ESM form and see if its getting big (bigger). That might be the issue.

Perhaps a 32u4 needs to be told not to send data..., I don't know, I'm not familiar with it. However I wold have though it would be a problem with the Arduino IDE's own monitor. May be someone knows something about these.

Alan

I can enter other messages in the entry line at the top of the ESM form of 4.0.3.0 and hit Send and they perform the expected action. If I enter #hist~int~10 or any other value the message stream looks like this

#hist~int~10
[ERR]#hist~int~10
[EX]Check message parametersIndex was outside the bounds of the array.

I have not been able to get 4.0.4.0 to work yet because I am not clear on what the directory structure and other files should be.