Home

Awesome

SerialDebug Library for Arduino

logo

arduino-library-badge GitHub release Codacy Badge platform badge GitHub contributions welcome Gitter chat GitHub issues star this repo

Improved serial debugging to Arduino, with with debug levels and simple software debugger, to see/change global variables, to add watch for these variables, or call a function, in runtime, using serial monitor or SerialDebugApp.

randomnerdtutorials Note: This image is from the tutorial for this library at randomnerdtutorials.com - Image by Sara Santos

Contents

About

Generally debugs messages in Arduino is done by Serial.print*, and show in this monitor serial, or another serial tool, as screen, pyserial, coolterm, etc.

The Arduino official IDE, not have debugger. Only way, until now, is using a another IDE, that can be paid, and a hardware debugger, as JTAG.

SerialDebug is a library to Improved serial debugging and simple software debugger to Arduino.

Yes, now we can use one debugger, simple but functional, and not need a extra hardware to do it.

News

2018-11-16

2018-10-26

Beta version

This is a beta version. Not yet fully tested, optimized, and documented.

This is a previous documentation. It will be better documented before first RC version.

Github

Contribute to this library development by creating an account on GitHub.

Please give a star, if you find this library usefull, this help a another people, discover it too.

Please add a issue for problems or suggestion.

And please join in the Gitter chat room (SerialDebug on Gitter).

Benefits

SerialDebug is bether than Arduino default serial debugging:

SerialDebugApp

SerialDebugApp is a freeware desktop app, companion for this library.

Note: this library is not depending on this software, you can use default serial monitor of Arduino IDE, or another program.

Why this app is an freeware and not open source ?

This app is based in my another commercial projects, through the serial port, control devices with the Arduino.

SerialDebugApp is a serial monitor, made for this library:

SerialDebugApp page: SerialDebugApp

How it looks

SerialDebug in Arduino serial monitor:

Youtube

SerialDebug in SerialDebugApp:

Youtube

SerialDebugApp: new version, with simple software debugger on screen:

Youtube

Commands

SerialDebug takes care of inputs from serial, and process predefined commands as:

  ? or help -> display these help of commands
  m -> show free memory
  n -> set debug level to none
  v -> set debug level to verbose
  d -> set debug level to debug
  i -> set debug level to info
  w -> set debug level to warning
  e -> set debug level to errors
  s -> silence (Not to show anything else, good for analysis)
  p -> profiler:
    p      -> show time between actual and last message (in millis)
    p min  -> show only if time is this minimal
  r -> repeat last command (in each debugHandle)
    r ? -> to show more help
  reset -> reset the Arduino board

  f -> call the function
      f ?  -> to show more help

  dbg [on|off] -> enable/disable the simple software debugger

  Only if debugger is enabled:
      g -> see/change global variables
        g ?  -> to show more help
      wa -> see/change watches for global variables
        wa ?  -> to show more help

  Not yet implemented:
    gpio -> see/control gpio

For simple software debugger:

- For functions:

  - To show help: f ?
  - To show: f [name|num]
  - To search with start of name (case insensitive): f name
  - To call it, just command: f [name|number] [arg]

- Enable/disable the debugger:

  - To enable: dbg on
  - To disable: dbg off

  Note: the debugger starts disabled, to avoid extra overhead to processing it
  You can enable it when need

- For global variables:

  - To show help: g ?
  - To show: g [name|num]
  - To search by start of name: g name
  - To change global variable, g [name|number] = value [y]
    note: y is to confirm it (without confirm message)

- For watches:

  - To show help: wa ?
  - To show: wa [num]
  - To add: wa a {global [name|number]} [==|!=|<|>|<=|>=|change] [value] [as]
    notes: change not need a value, and as -> set watch to stop always
  - To add cross (2 globals): wa ac {global [name|number]} [=|!=|<|>|<=|>=] {global [name|number]} [as]
  - To change: wa u {global [name|number]} [==|!=|<|>|<=|>=|change] [value] [as]
  - To change cross (not yet implemented)
  - To disable: wa d [num|all]
  - To enable: wa e [num|all]
  - To nonstop on watches: wa ns
  - To stop on watches: wa s

Notes:

Install

Just download or clone this repository.

Or for Arduino IDE, you can use the library manager to install and update the library.

<!-- For install help, please see: [https://www.arduino.cc/en/Guide/Libraries](https://www.arduino.cc/en/Guide/Libraries) -->

For install help, please click on this: arduino-library-badge

<!-- ![install](extras/readme_media/install.png) -->

For another IDE, or not using the library manager of Arduino IDE, I suggest you use a Github Desktop app to clone,it help to keep updated.

Usage

Note: In some boards, after upload if you see only dirty characteres in serial monitor, please reset the board. There is possibly some glitch in the serial monitor of Arduino

examples

Please open the examples to see it working:

  - Basic -> for basic usage, without debugger

  - Advanced/Avr -> for Arduino AVR arch. uses F() to save memory

  - Advanded/Others -> for new boards, with enough memory,
                      not use F(), due RAM is more faster than Flash memory

  - Disabled -> example of how disable features, or entire SerialDebug

Note: for low memory boards, as UNO, please open only the basic example.

To add SerialDebug to your Arduino project:

include

Place it, in top of code:

#include "SerialDebug.h" //https://github.com/JoaoLopesF/SerialDebug

setup

Setup code is only necessary for debugger elements. As this library not uses a hardware debugger, this codes are necessary to add this elements, into "simple software debugger" of SerialDebug.

For example, for functions:

// Add functions that can called from SerialDebug

if (debugAddFunctionVoid("benchInt", &benchInt) >= 0) {
  debugSetLastFunctionDescription("To run a benchmark of integers");
}
if (debugAddFunctionVoid("benchFloat", &benchFloat) >= 0) {
  debugSetLastFunctionDescription("To run a benchmark of float");
}
if (debugAddFunctionVoid("benchGpio", &benchGpio) >= 0) {
  debugSetLastFunctionDescription("To run a benchmark of Gpio operations");
}
if (debugAddFunctionVoid("benchAll", &benchAll) >= 0) {
  debugSetLastFunctionDescription("To run all benchmarks");
}

if (debugAddFunctionVoid("benchSerial", &benchSerial) >= 0) {
  debugSetLastFunctionDescription("To benchmarks standard Serial debug");
}
if (debugAddFunctionVoid("benchSerialDebug", &benchSerialDebug) >= 0) {
  debugSetLastFunctionDescription("To benchmarks SerialDebug");
}

if (debugAddFunctionStr("funcArgStr", &funcArgStr) >= 0) {
  debugSetLastFunctionDescription("To run with String arg");
}
if (debugAddFunctionChar("funcArgChar", &funcArgChar) >= 0) {
  debugSetLastFunctionDescription("To run with Character arg");
}
if (debugAddFunctionInt("funcArgInt", &funcArgInt) >= 0) {
  debugSetLastFunctionDescription("To run with Integer arg");
}

Or short use, if you not want descriptions:

// Add functions that can called from SerialDebug

debugAddFunctionVoid("benchInt", &benchInt);
debugAddFunctionVoid("benchFloat", &benchFloat);
debugAddFunctionVoid("benchGpio", &benchGpio);
debugAddFunctionVoid("benchAll", &benchAll);
debugAddFunctionVoid("benchSerial", &benchSerial);
debugAddFunctionVoid("benchSerialDebug", &benchSerialDebug);
debugAddFunctionStr("funcArgStr", &funcArgStr);
debugAddFunctionChar("funcArgChar", &funcArgChar);
debugAddFunctionInt("funcArgInt", &funcArgInt);
debugSetLastFunctionDescription("To run with Integer arg");

Note: If it is for old boards, as UNO, Leornardo, etc. You must use F() to save memory:

// Add functions that can called from SerialDebug

debugAddFunctionVoid(F("benchInt"), &benchInt);

Notes: It is too for all examples showed below

For global variables (note: only global ones):


// Add global variables that can showed/changed from SerialDebug
// Note: Only globlal, if pass local for SerialDebug, can be dangerous

if (debugAddGlobalUInt8_t("mRunSeconds", &mRunSeconds) >= 0) {
  debugSetLastGlobalDescription("Seconds of run time");
}
if (debugAddGlobalUInt8_t("mRunMinutes", &mRunMinutes) >= 0) {
  debugSetLastGlobalDescription("Minutes of run time");
}
if (debugAddGlobalUInt8_t("mRunHours", &mRunHours) >= 0) {
  debugSetLastGlobalDescription("Hours of run time");
}

// Note: easy way, no descriptions ....

debugAddGlobalBoolean("mBoolean", &mBoolean);
debugAddGlobalChar("mChar",       &mChar);
debugAddGlobalByte("mByte",       &mByte);
debugAddGlobalInt("mInt",         &mInt);
debugAddGlobalUInt("mUInt",       &mUInt);
debugAddGlobalLong("mLong",       &mLong);
debugAddGlobalULong("mULong",     &mULong);
debugAddGlobalFloat("mFloat",     &mFloat);
debugAddGlobalDouble("mDouble",   &mDouble);

debugAddGlobalString("mString",   &mString);

// Note: For char arrays, not use the '&'

debugAddGlobalCharArray("mCharArray", mCharArray);

// Note, here inform to show only 20 characteres of this string or char array

debugAddGlobalString("mStringLarge", &mStringLarge, 20);

debugAddGlobalCharArray("mCharArrayLarge",
                  mCharArrayLarge, 20);

// For arrays, need add for each item (not use loop for it, due the name can not by a variable)
// Notes: Is good added arrays in last order, to help see another variables
//        In next versions, we can have a helper to do it in one command

debugAddGlobalInt("mIntArray[0]", &mIntArray[0]);
debugAddGlobalInt("mIntArray[1]", &mIntArray[1]);
debugAddGlobalInt("mIntArray[2]", &mIntArray[2]);
debugAddGlobalInt("mIntArray[3]", &mIntArray[3]);
debugAddGlobalInt("mIntArray[4]", &mIntArray[4]);

And for watches (not for low memory boards, as UNO):

// Add watches for some global variables
// Note: watches can be added/changed in serial monitor too

// Watch -> mBoolean when changed (put 0 on value)

debugAddWatchBoolean("mBoolean", DEBUG_WATCH_CHANGED, 0);

// Watch -> mRunSeconds == 10

debugAddWatchUInt8_t("mRunSeconds", DEBUG_WATCH_EQUAL, 10);

// Watch -> mRunMinutes > 3

debugAddWatchUInt8_t("mRunMinutes", DEBUG_WATCH_GREAT, 3);

// Watch -> mRunMinutes == mRunSeconds (just for test)

debugAddWatchCross("mRunMinutes", DEBUG_WATCH_EQUAL, "mRunSeconds");

loop

// SerialDebug handle
// NOTE: if in inactive mode (until receive anything from serial),
// it show only messages of always or errors level type
// And the overhead during inactive mode is very much low

debugHandle();

converter

Note: Has a converter to do it for You: SerialDebugConverter

How use SerialDebug macros

Instead Serial.print*, use print* or debug* macros:

print*: easy to migrate and use, just replace each Serial.print for this

println*: same, but add a new line on output

debug*: w/ powerfull printf formatter, one command generate one serial line

See example of how convert it, in Benefits topic below.

Using macros to show debug:

debugA("**** Setup: initialized.");

// or

printlnA("**** Setup: initialized.");
debugE("* This is a message of debug level ERROR");

// or

printlnE("* This is a message of debug level ERROR");
debugV("* This is a message of debug level VERBOSE");
debugD("* This is a message of debug level DEBUG");
debugI("* This is a message of debug level INFO");
debugW("* This is a message of debug level WARNING");

// or

printlnV("* This is a message of debug level VERBOSE");
printlnD("* This is a message of debug level DEBUG");
printlnI("* This is a message of debug level INFO");
printlnW("* This is a message of debug level WARNING");

printf formatting (for debug* macros)

SerialDebug use prinf native (for Espressif boards), or implements it in depugPrintf function.

For Example:

debugA("This is a always - var %02d", var);
debugV("This is a verbose - var %02d", var);
debugD("This is a debug - var %02d", var);
debugI("This is a information - var %02d", var);
debugW("This is a warning - var %02d", var);
debugE("This is a error - var %02d", var);

See more about printf formatting: printf reference

Notes:

debugA("*** called with arg.: %s", str.c_str());


For AVR MCUs, as UNO, Leonardo, Mega and Esp8266, no have support to %f (format floats)

If you need this, use:

#ifndef ARDUINO_ARCH_AVR // Native float printf support
  debugV("mFloat = %0.3f", mFloat);
#else // For AVR and ESP8266, it is not supported, using String instead
  debugV("mFloat = %s", String(mFloat).c_str());
#endif

(in future versions of SerialDebug, can be have a better solution)

Note: this is only for debug* macros , thats uses printf

For _print* macros, no need extra codes:


printV("*** called with arg.: ");
printlnV(str);

printV("mFloat = ");
printlnV(mFloat);

Watches

Watches is usefull to warning when the content of global variable, is changed or reaches a certain condition.

How this works, without a real hardware debugger? :

This is done before each debug* show messages or in debugHandle function.

Tutorial

Have a nice tutorial about SerialDebug in randomnerdtutorials.com:

Please access this tutorial, to give more information about how use SerialDebug and SerialDebugApp.

Khow issues

Releases

0.9.82 - 2018-11-25

- corrected bug on debugHandleEvent

0.9.81 - 2018-11-16

- print macros now support second arg, e.g.: printlnA(10, HEX);
  thanks to @wjwieland to open a issue about this.

0.9.80 - 2018-11-15

- Few adjustments in header files

0.9.79 - 2018-11-06

- Examples and README update

0.9.78 - 2018-10-28

- Examples update

0.9.77 - 2018-10-26

- Adjustments for minimum mode
- #include stdarg, to avoid error in Arduino IDE 1.8.5 and Linux - thanks to @wd5gnr

0.9.76 - 2018-10-26

- #includes for Arduino.h corrected to work in Linux (case sensitive F.S.) - thanks @wd5gnr

0.9.75 - 2018-10-25

-  Few Adjustments (bug on declare prototype)

0.9.74 - 2018-10-25

- Adjustments to SerialDebugApp show debugger info in App
- Now low memory boards have debugger disabled by default, but enabled commands (debug level, help ...)
- Create an mode minimum to low memory boards - only debug output enabled to save memory

0.9.73 - 2018-10-24

- Adjustments to SerialDebugApp show debugger panel in App

0.9.72 - 2018-10-21

- Corrected bug on basic example

0.9.71 - 2018-10-19

- Just for new release, due problems on library.proprierties

0.9.7 - 2018-10-18

- Checking if debugger is enabled

0.9.6 - 2018-10-09

- New debug format output

0.9.5 - 2018-10-07

- New print macros
- Optimization on debugPrintf logic

0.9.4 - 2018-10-04

- Now debugger starts disabled

0.9.3 - 2018-10-01

- Few adjustments

0.9.2 - 2018-09-29

- Few adjustments

0.9.1 - 2018-09-28

- Few adjustments

0.9.0 - 2018-09-26

- First beta

Links

If you need a remote debug for ESP8266 or ESP32, see my other library -> RemoteDebug library

This library is made on Slober - the Eclipse for Arduino See it in -> Eclipse for Arduino

Thanks

Special thanks to:

- Arduino, for bring open hardware to us.

- Good people, that work hard, to bring to us excellent open source,
  as libraries, examples, etc..
  That inspire me to make new libraries, as SerialDebug, RemoteDebug, etc.

- Makers people, that works together as a big family.

End of README

Hit counter on this file, starting at 2019-03-03: HitCount