From 39b09167eb311e7edaf95020722b1bc0124ce03b Mon Sep 17 00:00:00 2001 From: Florian <1technophile@users.noreply.github.com> Date: Sun, 9 Feb 2020 13:45:46 +0100 Subject: [PATCH 01/32] add unsigned long format capability --- ArduinoLog.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ArduinoLog.cpp b/ArduinoLog.cpp index 4dba1aa..b66aa8b 100644 --- a/ArduinoLog.cpp +++ b/ArduinoLog.cpp @@ -169,6 +169,10 @@ void Logging::printFormat(const char format, va_list *args) { { _logOutput->print(va_arg(*args, long), DEC); } + else if (format == 'u') + { + _logOutput->print(va_arg(*args, unsigned long), DEC); + } else if (format == 'c') { _logOutput->print((char) va_arg(*args, int)); From a97f3eb6e2fa6baed12a89b9657f487007de2a56 Mon Sep 17 00:00:00 2001 From: Florian <1technophile@users.noreply.github.com> Date: Sun, 9 Feb 2020 14:00:07 +0100 Subject: [PATCH 02/32] add key for unsigned long values in help (%u) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index cd0bb23..bf2ffaf 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,7 @@ where the format string can be used to format the log variables * %c display as single character * %d display as integer value * %l display as long value +* %u display as unsigned long value * %x display as hexadecimal value * %X display as hexadecimal value prefixed by `0x` * %b display as binary number From d05e81f886b2db51ed84be0f18feaed2ad5e587e Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Mon, 17 May 2021 21:19:44 +0200 Subject: [PATCH 03/32] Updated to version 1.0.4 - Added ..ln functions (somehow got reverted) - Small fixes --- .gitignore | 359 +++++++++++++++++++++++++++++++++++++++++++ ArduinoLog.cpp | 17 +- ArduinoLog.h | 96 +++++++----- LICENSE.md | 2 +- examples/Log/Log.ino | 25 ++- keywords.txt | 11 ++ library.json | 2 +- library.properties | 2 +- 8 files changed, 469 insertions(+), 45 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..15ead68 --- /dev/null +++ b/.gitignore @@ -0,0 +1,359 @@ +#### Ignore file for Arduino as editted with Visual Micro + +## Windows +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows shortcuts +*.lnk + +## Linux +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +## MacOS +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +## Generated files +bin/ +gen/ +out/ +release/ + +## Visual Micro generated files +__vm/ + +# Local configuration file (sdk path, etc) +local.properties + +# Log Files +*.log + +##### Backup +*.bak +*.bck +*.gho +*.ori +*.orig +*.tmp + +##### Dropbox +# Dropbox settings and caches +.dropbox +.dropbox.attr +.dropbox.cache + +# Log file - the following switch allows to specify the file that will be +# used to write all messages from simulation: -l +*.log + +##### SVN +.svn/ + +##### TortoiseGit +# Project-level settings +/.tgitconfig + + +##### VisualStudioCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + + +##### VisualStudio +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual studio related SQlite files +*.db-shm +*.db-wal + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# Tabs Studio +*.tss + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +##### C++ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +##### C +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + + diff --git a/ArduinoLog.cpp b/ArduinoLog.cpp index b66aa8b..c66170c 100644 --- a/ArduinoLog.cpp +++ b/ArduinoLog.cpp @@ -5,7 +5,7 @@ /_/ \_\_|_\___/ \___/|___|_|\_|\___/|____\___/ \___| Log library for Arduino - version 1.0.3 + version 1.0.4 https://github.com/thijse/Arduino-Log Licensed under the MIT License . @@ -125,57 +125,70 @@ void Logging::print(const char *format, va_list args) { void Logging::printFormat(const char format, va_list *args) { #ifndef DISABLE_LOGGING + if (format == '\0') return; if (format == '%') { _logOutput->print(format); + return; } else if (format == 's') { register char *s = (char *)va_arg(*args, int); _logOutput->print(s); + return; } else if (format == 'S') { register __FlashStringHelper *s = (__FlashStringHelper *)va_arg(*args, int); _logOutput->print(s); + return; } else if (format == 'd' || format == 'i') { _logOutput->print(va_arg(*args, int), DEC); + return; } else if (format == 'D' || format == 'F') { _logOutput->print(va_arg(*args, double)); + return; } else if (format == 'x') { _logOutput->print(va_arg(*args, int), HEX); + return; } else if (format == 'X') { _logOutput->print("0x"); _logOutput->print(va_arg(*args, int), HEX); + return; } else if (format == 'b') { _logOutput->print(va_arg(*args, int), BIN); + return; } else if (format == 'B') { _logOutput->print("0b"); _logOutput->print(va_arg(*args, int), BIN); + return; } else if (format == 'l') { _logOutput->print(va_arg(*args, long), DEC); + return; } else if (format == 'u') { _logOutput->print(va_arg(*args, unsigned long), DEC); + return; } else if (format == 'c') { _logOutput->print((char) va_arg(*args, int)); + return; } else if(format == 't') { @@ -187,6 +200,7 @@ void Logging::printFormat(const char format, va_list *args) { { _logOutput->print("F"); } + return; } else if (format == 'T') { @@ -198,6 +212,7 @@ void Logging::printFormat(const char format, va_list *args) { { _logOutput->print(F("false")); } + return; } #endif } diff --git a/ArduinoLog.h b/ArduinoLog.h index 6cab7f0..eafdb3e 100644 --- a/ArduinoLog.h +++ b/ArduinoLog.h @@ -5,15 +5,13 @@ /_/ \_\_|_\___/ \___/|___|_|\_|\___/|____\___/ \___| Log library for Arduino - version 1.0.3 + version 1.0.4 https://github.com/thijse/Arduino-Log Licensed under the MIT License . */ - -#ifndef LOGGING_H -#define LOGGING_H +#pragma once #include #include #if defined(ARDUINO) && ARDUINO >= 100 @@ -39,7 +37,7 @@ typedef void (*printfunction)(Print*); #define LOG_LEVEL_VERBOSE 6 #define CR "\n" -#define LOGGING_VERSION 1_0_3 +#define LOGGING_VERSION 1_0_4 /** * Logging is a helper class to output informations over @@ -86,8 +84,8 @@ class Logging Logging() #ifndef DISABLE_LOGGING : _level(LOG_LEVEL_SILENT), - _showLevel(true), - _logOutput(NULL) + _showLevel(true), + _logOutput(NULL) #endif { @@ -163,12 +161,17 @@ class Logging * \param ... any number of variables * \return void */ - template void fatal(T msg, Args... args) - { + template void fatal(T msg, Args... args){ #ifndef DISABLE_LOGGING - printLevel(LOG_LEVEL_FATAL, msg, args...); + printLevel(LOG_LEVEL_FATAL, false, msg, args...); #endif - } + } + + template void fatalln(T msg, Args... args){ +#ifndef DISABLE_LOGGING + printLevel(LOG_LEVEL_FATAL, true, msg, args...); +#endif + } /** * Output an error message. Output message contains @@ -180,12 +183,17 @@ class Logging * \param ... any number of variables * \return void */ - template void error(T msg, Args... args){ + template void error(T msg, Args... args){ #ifndef DISABLE_LOGGING - printLevel(LOG_LEVEL_ERROR, msg, args...); + printLevel(LOG_LEVEL_ERROR, false, msg, args...); #endif - } - + } + + template void errorln(T msg, Args... args){ +#ifndef DISABLE_LOGGING + printLevel(LOG_LEVEL_ERROR, true, msg, args...); +#endif + } /** * Output a warning message. Output message contains * W: followed by original message @@ -196,12 +204,17 @@ class Logging * \param ... any number of variables * \return void */ - template void warning(T msg, Args...args) - { + template void warning(T msg, Args...args){ #ifndef DISABLE_LOGGING - printLevel(LOG_LEVEL_WARNING, msg, args...); + printLevel(LOG_LEVEL_WARNING, false, msg, args...); #endif - } + } + + template void warningln(T msg, Args...args){ +#ifndef DISABLE_LOGGING + printLevel(LOG_LEVEL_WARNING, true, msg, args...); +#endif + } /** * Output a notice message. Output message contains @@ -213,12 +226,17 @@ class Logging * \param ... any number of variables * \return void */ - template void notice(T msg, Args...args) - { + template void notice(T msg, Args...args){ #ifndef DISABLE_LOGGING - printLevel(LOG_LEVEL_NOTICE, msg, args...); + printLevel(LOG_LEVEL_NOTICE, false, msg, args...); #endif - } + } + + template void noticeln(T msg, Args...args){ +#ifndef DISABLE_LOGGING + printLevel(LOG_LEVEL_NOTICE, true, msg, args...); +#endif + } /** * Output a trace message. Output message contains @@ -230,10 +248,15 @@ class Logging * \param ... any number of variables * \return void */ - template void trace(T msg, Args... args) - { + template void trace(T msg, Args... args){ #ifndef DISABLE_LOGGING - printLevel(LOG_LEVEL_TRACE, msg, args...); + printLevel(LOG_LEVEL_TRACE, false, msg, args...); +#endif + } + + template void traceln(T msg, Args... args){ +#ifndef DISABLE_LOGGING + printLevel(LOG_LEVEL_TRACE, true, msg, args...); #endif } @@ -247,12 +270,17 @@ class Logging * \param ... any number of variables * \return void */ - template void verbose(T msg, Args... args) - { + template void verbose(T msg, Args... args){ #ifndef DISABLE_LOGGING - printLevel(LOG_LEVEL_VERBOSE, msg, args...); + printLevel(LOG_LEVEL_VERBOSE, false, msg, args...); #endif - } + } + + template void verboseln(T msg, Args... args){ +#ifndef DISABLE_LOGGING + printLevel(LOG_LEVEL_VERBOSE, true, msg, args...); +#endif + } private: void print(const char *format, va_list args); @@ -261,7 +289,7 @@ class Logging void printFormat(const char format, va_list *args); - template void printLevel(int level, T msg, ...) + template void printLevel(int level, bool cr, T msg, ...) { #ifndef DISABLE_LOGGING if (level > _level) @@ -283,7 +311,7 @@ class Logging va_list args; va_start(args, msg); print(msg, args); - + if (cr) { _logOutput->print(CR); } if(_suffix != NULL) { _suffix(_logOutput); @@ -301,6 +329,4 @@ class Logging #endif }; -extern Logging Log; -#endif - +extern Logging Log; \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md index b4d0fa4..2383777 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017,2018 Thijs Elenbaas, MrRobot62, rahuldeo2047, NOX73, dhylands, Josha +Copyright (c) 2017,2018,2021 Thijs Elenbaas, MrRobot62, rahuldeo2047, NOX73, dhylands, Josha blemasle, mfalkvidd Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/examples/Log/Log.ino b/examples/Log/Log.ino index e783d2b..f534e72 100644 --- a/examples/Log/Log.ino +++ b/examples/Log/Log.ino @@ -1,8 +1,15 @@ #include +/* + _ ___ ___ _ _ ___ _ _ ___ _ ___ ___ + /_\ | _ \ \| | | |_ _| \| |/ _ \| | / _ \ / __| + / _ \| / |) | |_| || || .` | (_) | |_| (_) | (_ | + /_/ \_\_|_\___/ \___/|___|_|\_|\___/|____\___/ \___| + + Log library example + Licensed under the MIT License . + + This example sketch shows most of the features of the ArduinoLog library -/*! -* This example sketch shows most of the features of the ArduinoLog library -* */ @@ -28,7 +35,7 @@ void setup() { Log.begin(LOG_LEVEL_VERBOSE, &Serial); //Log.setPrefix(printTimestamp); // Uncomment to get timestamps as prefix - //Log.setSuffix(printNewline); // Uncomment to get newline as suffix + //Log.setSuffix(printNewline); // Uncomment to get newline as suffix //Start logging @@ -48,7 +55,7 @@ void loop() { floatValue = 12.34; doubleValue= 1234.56789; - //__FlashStringHelper cannot be declared oustide a function + //__FlashStringHelper cannot be declared outside a function const __FlashStringHelper * flashCharArray2 = F("this is a string"); Log.notice ( "Log as Info with integer values : %d, %d" CR , intValue1, intValue2); @@ -68,11 +75,17 @@ void loop() { Log.notice ( "Log as Info with double value : %D" CR , doubleValue); Log.notice (F("Log as Debug with mixed values : %d, %d, %l, %l, %t, %T" CR ), intValue1 , intValue2, longValue1, longValue2, boolValue1, boolValue2); + Log.noticeln ( "Log as Info with integer values : %d, %d" , intValue1, intValue2); Log.trace ( "Log as Trace with bool value : %T" CR , boolValue1); + Log.traceln ( "Log as Trace with bool value : %T" , boolValue1); Log.warning ( "Log as Warning with bool value : %T" CR , boolValue1); + Log.warningln( "Log as Warning with bool value : %T" , boolValue1); Log.error ( "Log as Error with bool value : %T" CR , boolValue1); + Log.errorln ( "Log as Error with bool value : %T" , boolValue1); Log.fatal ( "Log as Fatal with bool value : %T" CR , boolValue1); - Log.verbose (F("Log as Verbose with bool value : %T" CR CR CR ), boolValue2); + Log.fatalln ( "Log as Fatal with bool value : %T" , boolValue1); + Log.verboseln(F("Log as Verbose with bool value : %T" ), boolValue2); + Log.verbose (F("Log as Verbose with bool value : %T" CR CR CR ), boolValue2); delay(5000); } diff --git a/keywords.txt b/keywords.txt index f338673..f627cbc 100644 --- a/keywords.txt +++ b/keywords.txt @@ -15,12 +15,22 @@ Log KEYWORD1 # Methods and Functions (KEYWORD2) ####################################### fatal KEYWORD2 +fatalln KEYWORD2 error KEYWORD2 +errorln KEYWORD2 warning KEYWORD2 +warningln KEYWORD2 notice KEYWORD2 +noticeln KEYWORD2 trace KEYWORD2 +traceln KEYWORD2 verbose KEYWORD2 +verboseln KEYWORD2 begin KEYWORD2 +setLevel KEYWORD2 +getLevel KEYWORD2 +setShowLevel KEYWORD2 +getShowLevel KEYWORD2 setPrefix KEYWORD2 setSuffix KEYWORD2 @@ -28,6 +38,7 @@ setSuffix KEYWORD2 # Instances (KEYWORD2) ####################################### Logging KEYWORD2 +Log KEYWORD2 ####################################### # Constants (LITERAL1) diff --git a/library.json b/library.json index 7b61150..709a31b 100644 --- a/library.json +++ b/library.json @@ -2,7 +2,7 @@ "name": "ArduinoLog", "keywords": "logging, debug, log, log levels, AVR, ESP8266", "description": "ArduinoLog is a minimalistic logging framework to help the programmer output log statements to a chosen output target. ArduinoLog is designed so that log statements can remain in the code with minimal performance cost. In order to facilitate this the loglevel can be adjusted, and if the code is completely tested all logging code can be compiled out. Tested for AVR and ESP8266 boards.", - "version": "1.0.3", + "version": "1.0.4", "authors": { "name": "Thijs Elenbaas", "url": "https://github.com/thijse", diff --git a/library.properties b/library.properties index a203815..8c9861f 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ArduinoLog -version=1.0.3 +version=1.0.4 author=Thijs Elenbaas maintainer=Thijs Elenbaas sentence=Small logging framework From f8c352cdfd6b59bf0e8ab9438f39d1f80194c8ee Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Mon, 17 May 2021 22:02:21 +0200 Subject: [PATCH 04/32] Updated prefix & suffix example Added ESP32 tested statement --- ArduinoLog.h | 6 +- LICENSE.md | 4 +- README.md | 3 +- examples/Log/Log.ino | 207 ++++++++++++++++++++++--------------------- 4 files changed, 115 insertions(+), 105 deletions(-) diff --git a/ArduinoLog.h b/ArduinoLog.h index eafdb3e..908ddc1 100644 --- a/ArduinoLog.h +++ b/ArduinoLog.h @@ -311,11 +311,15 @@ class Logging va_list args; va_start(args, msg); print(msg, args); - if (cr) { _logOutput->print(CR); } + if(_suffix != NULL) { _suffix(_logOutput); } + if (cr) + { + _logOutput->print(CR); + } #endif } diff --git a/LICENSE.md b/LICENSE.md index 2383777..554b7df 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,7 +1,7 @@ MIT License -Copyright (c) 2017,2018,2021 Thijs Elenbaas, MrRobot62, rahuldeo2047, NOX73, dhylands, Josha - blemasle, mfalkvidd +Copyright (c) 2017,2018,2021 Thijs Elenbaas, MrRobot62, rahuldeo2047, NOX73, + dhylands, Josha, blemasle, mfalkvidd Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index bf2ffaf..6ed9d2c 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ ArduinoLog is a minimalistic framework to help the programmer output log stateme * All Arduino boards (Uno, Due, Mini, Micro, Yun...) * ESP8266 +* ESP32 ## Downloading @@ -175,4 +176,4 @@ Bugfixes & features by ## Copyright -ArduinoLog is provided Copyright © 2017,2018, 2019 under MIT License. +ArduinoLog is provided Copyright © 2017,2018, 2019, 2021 under MIT License. diff --git a/examples/Log/Log.ino b/examples/Log/Log.ino index f534e72..8815aed 100644 --- a/examples/Log/Log.ino +++ b/examples/Log/Log.ino @@ -1,101 +1,106 @@ -#include -/* - _ ___ ___ _ _ ___ _ _ ___ _ ___ ___ - /_\ | _ \ \| | | |_ _| \| |/ _ \| | / _ \ / __| - / _ \| / |) | |_| || || .` | (_) | |_| (_) | (_ | - /_/ \_\_|_\___/ \___/|___|_|\_|\___/|____\___/ \___| - - Log library example - Licensed under the MIT License . - - This example sketch shows most of the features of the ArduinoLog library - -*/ - - -int intValue1 , intValue2; -long longValue1, longValue2; -bool boolValue1, boolValue2; -const char * charArray = "this is a string"; -const char flashCharArray1[] PROGMEM = "this is a string"; -String stringValue1 = "this is a string"; -float floatValue; -double doubleValue; - -void setup() { - // Set up serial port and wait until connected - Serial.begin(9600); - while(!Serial && !Serial.available()){} - randomSeed(analogRead(0)); - // Pass log level, whether to show log level, and print interface. - // Available levels are: - // LOG_LEVEL_SILENT, LOG_LEVEL_FATAL, LOG_LEVEL_ERROR, LOG_LEVEL_WARNING, LOG_LEVEL_NOTICE, LOG_LEVEL_TRACE, LOG_LEVEL_VERBOSE - // Note: if you want to fully remove all logging code, uncomment #define DISABLE_LOGGING in Logging.h - // this will significantly reduce your project size - - Log.begin(LOG_LEVEL_VERBOSE, &Serial); - //Log.setPrefix(printTimestamp); // Uncomment to get timestamps as prefix - //Log.setSuffix(printNewline); // Uncomment to get newline as suffix - - //Start logging - - Log.notice(F(CR "******************************************" CR)); // Info string with Newline - Log.notice( "*** Logging example " CR); // Info string in flash memory - Log.notice(F("******************* ")); Log.notice("*********************** " CR); // two info strings without newline -} - -void loop() { - // set up some random variables - intValue1 = random(100); - intValue2 = random(10000); - longValue1 = random(1000000); - longValue2 = random(100000000); - boolValue1 = random(2)==0; - boolValue2 = random(2)==1; - floatValue = 12.34; - doubleValue= 1234.56789; - - //__FlashStringHelper cannot be declared outside a function - const __FlashStringHelper * flashCharArray2 = F("this is a string"); - - Log.notice ( "Log as Info with integer values : %d, %d" CR , intValue1, intValue2); - Log.notice (F("Log as Info with hex values : %x, %X" CR ), intValue1, intValue1); - Log.notice ( "Log as Info with hex values : %x, %X" CR , intValue2, intValue2); - Log.notice (F("Log as Info with binary values : %b, %B" CR ), intValue1, intValue1); - Log.notice ( "Log as Info with binary values : %b, %B" CR , intValue2, intValue2); - Log.notice (F("Log as Info with long values : %l, %l" CR ), longValue1, longValue2); - Log.notice ( "Log as Info with bool values : %t, %T" CR , boolValue1, boolValue2); - Log.notice (F("Log as Info with string value : %s" CR ), charArray); - Log.notice ( "Log as Info with Flash string value : %S" CR , flashCharArray1); - Log.notice ( "Log as Info with Flash string value : %S" CR , flashCharArray2); - Log.notice ( "Log as Info with string value : %s" CR , stringValue1.c_str()); - Log.notice (F("Log as Info with float value : %F" CR ), floatValue); - Log.notice ( "Log as Info with float value : %F" CR , floatValue); - Log.notice (F("Log as Info with double value : %D" CR ), doubleValue); - Log.notice ( "Log as Info with double value : %D" CR , doubleValue); - Log.notice (F("Log as Debug with mixed values : %d, %d, %l, %l, %t, %T" CR ), intValue1 , intValue2, - longValue1, longValue2, boolValue1, boolValue2); - Log.noticeln ( "Log as Info with integer values : %d, %d" , intValue1, intValue2); - Log.trace ( "Log as Trace with bool value : %T" CR , boolValue1); - Log.traceln ( "Log as Trace with bool value : %T" , boolValue1); - Log.warning ( "Log as Warning with bool value : %T" CR , boolValue1); - Log.warningln( "Log as Warning with bool value : %T" , boolValue1); - Log.error ( "Log as Error with bool value : %T" CR , boolValue1); - Log.errorln ( "Log as Error with bool value : %T" , boolValue1); - Log.fatal ( "Log as Fatal with bool value : %T" CR , boolValue1); - Log.fatalln ( "Log as Fatal with bool value : %T" , boolValue1); - Log.verboseln(F("Log as Verbose with bool value : %T" ), boolValue2); - Log.verbose (F("Log as Verbose with bool value : %T" CR CR CR ), boolValue2); - delay(5000); -} - -void printTimestamp(Print* _logOutput) { - char c[12]; - int m = sprintf(c, "%10lu ", millis()); - _logOutput->print(c); -} - -void printNewline(Print* _logOutput) { - _logOutput->print('\n'); -} - +#include +/* + _ ___ ___ _ _ ___ _ _ ___ _ ___ ___ + /_\ | _ \ \| | | |_ _| \| |/ _ \| | / _ \ / __| + / _ \| / |) | |_| || || .` | (_) | |_| (_) | (_ | + /_/ \_\_|_\___/ \___/|___|_|\_|\___/|____\___/ \___| + + Log library example + Licensed under the MIT License . + + This example sketch shows most of the features of the ArduinoLog library + +*/ + + +int intValue1 , intValue2; +long longValue1, longValue2; +bool boolValue1, boolValue2; +const char * charArray = "this is a string"; +const char flashCharArray1[] PROGMEM = "this is a string"; +String stringValue1 = "this is a string"; +float floatValue; +double doubleValue; + +void setup() { + // Set up serial port and wait until connected + Serial.begin(9600); + while(!Serial && !Serial.available()){} + randomSeed(analogRead(0)); + // Pass log level, whether to show log level, and print interface. + // Available levels are: + // LOG_LEVEL_SILENT, LOG_LEVEL_FATAL, LOG_LEVEL_ERROR, LOG_LEVEL_WARNING, LOG_LEVEL_NOTICE, LOG_LEVEL_TRACE, LOG_LEVEL_VERBOSE + // Note: if you want to fully remove all logging code, uncomment #define DISABLE_LOGGING in Logging.h + // this will significantly reduce your project size + + Log.begin(LOG_LEVEL_VERBOSE, &Serial); + + + //Start logging + + Log.notice(F(CR "******************************************" CR)); // Info string with Newline + Log.notice( "*** Logging example " CR); // Info string in flash memory + Log.notice(F("******************* ")); Log.notice("*********************** " CR); // two info strings without newline +} + +void loop() { + // set up some random variables + intValue1 = random(100); + intValue2 = random(10000); + longValue1 = random(1000000); + longValue2 = random(100000000); + boolValue1 = random(2)==0; + boolValue2 = random(2)==1; + floatValue = 12.34; + doubleValue= 1234.56789; + + //__FlashStringHelper cannot be declared outside a function + const __FlashStringHelper * flashCharArray2 = F("this is a string"); + + Log.notice ( "Log as Info with integer values : %d, %d" CR , intValue1, intValue2); + Log.notice (F("Log as Info with hex values : %x, %X" CR ), intValue1, intValue1); + Log.notice ( "Log as Info with hex values : %x, %X" CR , intValue2, intValue2); + Log.notice (F("Log as Info with binary values : %b, %B" CR ), intValue1, intValue1); + Log.notice ( "Log as Info with binary values : %b, %B" CR , intValue2, intValue2); + Log.notice (F("Log as Info with long values : %l, %l" CR ), longValue1, longValue2); + Log.notice ( "Log as Info with bool values : %t, %T" CR , boolValue1, boolValue2); + Log.notice (F("Log as Info with string value : %s" CR ), charArray); + Log.notice ( "Log as Info with Flash string value : %S" CR , flashCharArray1); + Log.notice ( "Log as Info with Flash string value : %S" CR , flashCharArray2); + Log.notice ( "Log as Info with string value : %s" CR , stringValue1.c_str()); + Log.notice (F("Log as Info with float value : %F" CR ), floatValue); + Log.notice ( "Log as Info with float value : %F" CR , floatValue); + Log.notice (F("Log as Info with double value : %D" CR ), doubleValue); + Log.notice ( "Log as Info with double value : %D" CR , doubleValue); + Log.notice (F("Log as Debug with mixed values : %d, %d, %l, %l, %t, %T" CR ), intValue1 , intValue2, + longValue1, longValue2, boolValue1, boolValue2); + + Log.trace ( "Log as Trace with bool value : %T" CR , boolValue1); + Log.traceln ( "Log as Trace with bool value : %T" , boolValue1); + Log.warning ( "Log as Warning with bool value : %T" CR , boolValue1); + Log.warningln( "Log as Warning with bool value : %T" , boolValue1); + Log.error ( "Log as Error with bool value : %T" CR , boolValue1); + Log.errorln ( "Log as Error with bool value : %T" , boolValue1); + Log.fatal ( "Log as Fatal with bool value : %T" CR , boolValue1); + Log.fatalln ( "Log as Fatal with bool value : %T" , boolValue1); + Log.verboseln(F("Log as Verbose with bool value : %T" ), boolValue2); + Log.verbose (F("Log as Verbose with bool value : %T" CR ), boolValue2); + + Log.setPrefix(printTimestamp); // set timestamp as prefix + Log.setSuffix(printCarret); // set carret as suffix + Log.verboseln(F("Log with suffix & prefix")); + Log.setPrefix(NULL); // set timestamp as prefix + Log.setSuffix(NULL); // set carret as suffix + + delay(5000); +} + +void printTimestamp(Print* _logOutput) { + char c[12]; + int m = sprintf(c, "%10lu ", millis()); + _logOutput->print(c); +} + +void printCarret(Print* _logOutput) { + _logOutput->print('>'); +} From c0f9ec3d40158fdfb85118c9ba295e1cdcd11fab Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Mon, 17 May 2021 22:35:18 +0200 Subject: [PATCH 05/32] Added clearSuffix & clearPrefix --- ArduinoLog.cpp | 14 ++++++++++++++ ArduinoLog.h | 14 ++++++++++++++ keywords.txt | 2 ++ 3 files changed, 30 insertions(+) diff --git a/ArduinoLog.cpp b/ArduinoLog.cpp index c66170c..304b30d 100644 --- a/ArduinoLog.cpp +++ b/ArduinoLog.cpp @@ -79,6 +79,13 @@ void Logging::setPrefix(printfunction f) #endif } +void Logging::clearPrefix() +{ +#ifndef DISABLE_LOGGING + _prefix = nullptr; +#endif +} + void Logging::setSuffix(printfunction f) { #ifndef DISABLE_LOGGING @@ -86,6 +93,13 @@ void Logging::setSuffix(printfunction f) #endif } +void Logging::clearSuffix() +{ +#ifndef DISABLE_LOGGING + _prefix = nullptr; +#endif +} + void Logging::print(const __FlashStringHelper *format, va_list args) { #ifndef DISABLE_LOGGING diff --git a/ArduinoLog.h b/ArduinoLog.h index 908ddc1..c35f34d 100644 --- a/ArduinoLog.h +++ b/ArduinoLog.h @@ -143,6 +143,13 @@ class Logging */ void setPrefix(printfunction f); + /** + * clears prefix. + * + * \return void + */ + void clearPrefix(); + /** * Sets a function to be called after each log command. * @@ -151,6 +158,13 @@ class Logging */ void setSuffix(printfunction f); + /** + * clears suffix. + * + * \return void + */ + void clearSuffix(); + /** * Output a fatal error message. Output message contains * F: followed by original message diff --git a/keywords.txt b/keywords.txt index f627cbc..2287ce6 100644 --- a/keywords.txt +++ b/keywords.txt @@ -33,6 +33,8 @@ setShowLevel KEYWORD2 getShowLevel KEYWORD2 setPrefix KEYWORD2 setSuffix KEYWORD2 +clearPrefix KEYWORD2 +clearSuffix KEYWORD2 ####################################### # Instances (KEYWORD2) From 2d9fdbe4e039f4fe34547ac4d101290142641484 Mon Sep 17 00:00:00 2001 From: kendall Date: Sun, 10 Jan 2021 14:09:19 -0800 Subject: [PATCH 06/32] Copy the va_list to a temporary variable to work around a problem where the call doesn't work, on some architectures, if one of the list items is an array. --- ArduinoLog.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/ArduinoLog.cpp b/ArduinoLog.cpp index 304b30d..5a08ad4 100644 --- a/ArduinoLog.cpp +++ b/ArduinoLog.cpp @@ -104,36 +104,62 @@ void Logging::print(const __FlashStringHelper *format, va_list args) { #ifndef DISABLE_LOGGING PGM_P p = reinterpret_cast(format); +// This copy is only necessary on some architectures (x86) to change a passed +// array in to a va_list. +#ifdef __x86_64__ + va_list args_copy; + va_copy(args_copy, args); +#endif char c = pgm_read_byte(p++); for(;c != 0; c = pgm_read_byte(p++)) { if (c == '%') { c = pgm_read_byte(p++); +#ifdef __x86_64__ + printFormat(c, &args_copy); +#else printFormat(c, &args); +#endif } else { _logOutput->print(c); } } +#ifdef __x86_64__ + va_end(args_copy); +#endif #endif } void Logging::print(const char *format, va_list args) { #ifndef DISABLE_LOGGING +// This copy is only necessary on some architectures (x86) to change a passed +// array in to a va_list. +#ifdef __x86_64__ + va_list args_copy; + va_copy(args_copy, args); +#endif for (; *format != 0; ++format) { if (*format == '%') { ++format; +#ifdef __x86_64__ + printFormat(*format, &args_copy); +#else printFormat(*format, &args); +#endif } else { _logOutput->print(*format); } } +#ifdef __x86_64__ + va_end(args_copy); +#endif #endif } From 0dd1d1c9b0ffa2b5e19ff4d0e715217453251fec Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Sat, 22 May 2021 14:17:52 +0200 Subject: [PATCH 07/32] Added ArduinoLog logo --- Images/logo.png | Bin 0 -> 27227 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Images/logo.png diff --git a/Images/logo.png b/Images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..88f447565eac78196a4ef95ed2897ed668bb17f2 GIT binary patch literal 27227 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

=Wgw8Odv#I;^4pSs$5 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 kMf^`M)6o3?2i*EyWseL( Date: Sat, 22 May 2021 14:20:46 +0200 Subject: [PATCH 08/32] Added logo to README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6ed9d2c..ced2c66 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +![ArduinoLog logo](/Images/logo.png?raw=true ) ArduinoLog - C++ Log library for Arduino devices ==================== [![Build Status](https://travis-ci.org/thijse/Arduino-Log.svg?branch=master)](https://travis-ci.org/thijse/Arduino-Log) From 431792a7e91646b5112e43c29e4cdb65f5e4fc59 Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Sat, 22 May 2021 18:52:33 +0200 Subject: [PATCH 09/32] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ced2c66..312d6db 100644 --- a/README.md +++ b/README.md @@ -115,8 +115,8 @@ where the format string can be used to format the log variables * %D,%F display as double value ``` - Newlines can be added using the CR keyword or by using the ...ln version of each of the log functions. - + Newlines can be added using the CR keyword or by using the `...ln` version of each of the log functions. The difference when using the `...ln` is that the newline is placed after suffix, and only a single newline can be added. + ### Storing messages in Flash memory Flash strings log variables can be stored and reused at several places to reduce final hex size. From 1e661cde4528fc515d2668ee1de74aa83592ab9e Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Sat, 22 May 2021 18:54:51 +0200 Subject: [PATCH 10/32] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 312d6db..079c62f 100644 --- a/README.md +++ b/README.md @@ -133,7 +133,7 @@ If you want to declare that string globally (outside of a function), you will ne const char LOG_AS[] PROGMEM = "Log as "; void logError() { - Log.error ( "%S Error with binary values : %b, %B"CR , PSTRPTR(LOG_AS), 23 , 345808); + Log.error ( "%S Error with binary values : %b, %B"CR , PSTRPTR(LOG_AS), 23 , 345808); } ``` From 47e03c226cfc694c48c6ff432996091af765a382 Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Sat, 22 May 2021 22:52:12 +0200 Subject: [PATCH 11/32] - Added cmake, Intellibrains, PlatformIO folders to ignore file - Added PGM stubs - Use Arduino.h in most cases --- .gitignore | 8 ++++++++ ArduinoLog.h | 19 ++++++++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 15ead68..b168b8c 100644 --- a/.gitignore +++ b/.gitignore @@ -356,4 +356,12 @@ Module.symvers Mkfile.old dkms.conf +# Cmake +cmake*/ +CMakeListsPrivate.txt +# PlatformIO IDE data +.pio/ + +# Jetbrains IDE configuration +.idea/ \ No newline at end of file diff --git a/ArduinoLog.h b/ArduinoLog.h index c35f34d..fd0f869 100644 --- a/ArduinoLog.h +++ b/ArduinoLog.h @@ -14,15 +14,24 @@ Licensed under the MIT License . #pragma once #include #include -#if defined(ARDUINO) && ARDUINO >= 100 - #include "Arduino.h" -#else + +// Non standard: Arduino.h also chosen if ARDUINO is not defined. To facilitate use in non-Arduino test environments +#if ARDUINO < 100 #include "WProgram.h" +#else + #include "Arduino.h" +#endif + +// PGM stubs to facilitate use in non-Arduino test environments +#ifndef PGM_P +#define PGM_P const char * +#define pgm_read_byte(addr) (*(const unsigned char *)(addr)) +#define PSTR(str) (str) +#define F(string_literal) (reinterpret_cast(PSTR(string_literal))) #endif typedef void (*printfunction)(Print*); -//#include -//#include + // ************************************************************************* // Uncomment line below to fully disable logging, and reduce project size // ************************************************************************ From 6b4e36061014bde89ebe8c7ad75a81f3197f1b20 Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Sat, 22 May 2021 23:28:00 +0200 Subject: [PATCH 12/32] Added additional formatting parameters --- ArduinoLog.cpp | 32 +++++++++++++++++--------------- README.md | 7 ++++--- examples/Log/Log.ino | 5 ++++- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/ArduinoLog.cpp b/ArduinoLog.cpp index 5a08ad4..dcbc257 100644 --- a/ArduinoLog.cpp +++ b/ArduinoLog.cpp @@ -169,40 +169,38 @@ void Logging::printFormat(const char format, va_list *args) { if (format == '%') { _logOutput->print(format); - return; } else if (format == 's') { register char *s = (char *)va_arg(*args, int); _logOutput->print(s); - return; } else if (format == 'S') { register __FlashStringHelper *s = (__FlashStringHelper *)va_arg(*args, int); _logOutput->print(s); - return; } else if (format == 'd' || format == 'i') { _logOutput->print(va_arg(*args, int), DEC); - return; } else if (format == 'D' || format == 'F') { _logOutput->print(va_arg(*args, double)); - return; } else if (format == 'x') { _logOutput->print(va_arg(*args, int), HEX); - return; } else if (format == 'X') - { + { _logOutput->print("0x"); - _logOutput->print(va_arg(*args, int), HEX); - return; + //_logOutput->print(va_arg(*args, int), HEX); + register uint16_t h = (uint16_t) va_arg( *args, int ); + if (h<0xFFF) _logOutput->print('0'); + if (h<0xFF ) _logOutput->print('0'); + if (h<0xF ) _logOutput->print('0'); + _logOutput->print(h,HEX); } else if (format == 'b') { @@ -213,23 +211,29 @@ void Logging::printFormat(const char format, va_list *args) { { _logOutput->print("0b"); _logOutput->print(va_arg(*args, int), BIN); - return; } else if (format == 'l') { _logOutput->print(va_arg(*args, long), DEC); - return; } else if (format == 'u') { _logOutput->print(va_arg(*args, unsigned long), DEC); - return; } else if (format == 'c') { _logOutput->print((char) va_arg(*args, int)); - return; } + else if( format == 'C' ) { + register char c = (char) va_arg( *args, int ); + if (c>=0x20 && c<0x7F) { + _logOutput->print(c); + } else { + _logOutput->print("0x"); + if (c<0xF) _logOutput->print('0'); + _logOutput->print(c, HEX); + } + } else if(format == 't') { if (va_arg(*args, int) == 1) @@ -240,7 +244,6 @@ void Logging::printFormat(const char format, va_list *args) { { _logOutput->print("F"); } - return; } else if (format == 'T') { @@ -252,7 +255,6 @@ void Logging::printFormat(const char format, va_list *args) { { _logOutput->print(F("false")); } - return; } #endif } diff --git a/README.md b/README.md index 079c62f..fb083dd 100644 --- a/README.md +++ b/README.md @@ -103,13 +103,14 @@ where the format string can be used to format the log variables * %s display as string (char*) * %S display as string from flash memory (__FlashStringHelper* or char[] PROGMEM) * %c display as single character +* %C display as single character or as hexadecimal value (prefixed by `0x`) if not a printable character * %d display as integer value * %l display as long value * %u display as unsigned long value * %x display as hexadecimal value -* %X display as hexadecimal value prefixed by `0x` +* %X display as hexadecimal value prefixed by `0x` and leading zeros * %b display as binary number -* %B display as binary number, prefixed by `0b' +* %B display as binary number, prefixed by `0b` * %t display as boolean value "t" or "f" * %T display as boolean value "true" or "false" * %D,%F display as double value @@ -168,7 +169,7 @@ Bugfixes & features by * [Jos Hanon](https://github.com/Josha) * [Bertrand Lemasle](https://github.com/blemasle) * [Mikael Falkvidd](https://github.com/mfalkvidd) - +* [bitli] https://github.com/bitli) ## On using and modifying libraries diff --git a/examples/Log/Log.ino b/examples/Log/Log.ino index 8815aed..bd638a0 100644 --- a/examples/Log/Log.ino +++ b/examples/Log/Log.ino @@ -16,6 +16,7 @@ int intValue1 , intValue2; long longValue1, longValue2; bool boolValue1, boolValue2; +const char charNotPrintable = 0x8B; const char * charArray = "this is a string"; const char flashCharArray1[] PROGMEM = "this is a string"; String stringValue1 = "this is a string"; @@ -64,6 +65,8 @@ void loop() { Log.notice ( "Log as Info with binary values : %b, %B" CR , intValue2, intValue2); Log.notice (F("Log as Info with long values : %l, %l" CR ), longValue1, longValue2); Log.notice ( "Log as Info with bool values : %t, %T" CR , boolValue1, boolValue2); + Log.notice (F("Log as Info with char value : %c" CR ), charArray[0]); + Log.notice ( "Log as Info with char value : %C" CR , charNotPrintable); Log.notice (F("Log as Info with string value : %s" CR ), charArray); Log.notice ( "Log as Info with Flash string value : %S" CR , flashCharArray1); Log.notice ( "Log as Info with Flash string value : %S" CR , flashCharArray2); @@ -103,4 +106,4 @@ void printTimestamp(Print* _logOutput) { void printCarret(Print* _logOutput) { _logOutput->print('>'); -} +} \ No newline at end of file From 6eba9553cf2a918c0b507d7f7d31f90ba73711cc Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Sun, 23 May 2021 11:56:13 +0200 Subject: [PATCH 13/32] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fb083dd..0fabe24 100644 --- a/README.md +++ b/README.md @@ -169,7 +169,7 @@ Bugfixes & features by * [Jos Hanon](https://github.com/Josha) * [Bertrand Lemasle](https://github.com/blemasle) * [Mikael Falkvidd](https://github.com/mfalkvidd) -* [bitli] https://github.com/bitli) +* [bitli] (https://github.com/bitli) ## On using and modifying libraries From c2df66a03aa597b4566ddd9c502900c925a41950 Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Sun, 23 May 2021 15:28:07 +0200 Subject: [PATCH 14/32] Added ability to log Printable objects --- ArduinoLog.h | 10 ++++++++++ README.md | 8 ++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/ArduinoLog.h b/ArduinoLog.h index fd0f869..acb379e 100644 --- a/ArduinoLog.h +++ b/ArduinoLog.h @@ -310,6 +310,11 @@ class Logging void print(const __FlashStringHelper *format, va_list args); + void print(const Printable& obj, va_list& args) + { + _logOutput->print(obj); + } + void printFormat(const char format, va_list *args); template void printLevel(int level, bool cr, T msg, ...) @@ -319,6 +324,11 @@ class Logging { return; } + if (level < LOG_LEVEL_SILENT) + { + level = LOG_LEVEL_SILENT; + } + if (_prefix != NULL) { diff --git a/README.md b/README.md index fb083dd..a7ffc05 100644 --- a/README.md +++ b/README.md @@ -169,8 +169,12 @@ Bugfixes & features by * [Jos Hanon](https://github.com/Josha) * [Bertrand Lemasle](https://github.com/blemasle) * [Mikael Falkvidd](https://github.com/mfalkvidd) -* [bitli] https://github.com/bitli) - +* [Rowan Goemans] (https://github.com/rowanG077) +* [Nils Bokermann] (https://github.com/sanddorn) +* [Florian] (https://github.com/1technophile) +* [wrong-kendall] (https://github.com/wrong-kendall) +* [bitli] (https://github.com/bitli) +* [ChristianBauerAMDC] (https://github.com/bitli) ## On using and modifying libraries - [http://www.arduino.cc/en/Main/Libraries](http://www.arduino.cc/en/Main/Libraries) From 31fae5797fba89a578d87495361b1fdf8b7ede6a Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Sun, 23 May 2021 15:33:52 +0200 Subject: [PATCH 15/32] Updated README.md --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 86a70ab..61fb8e5 100644 --- a/README.md +++ b/README.md @@ -169,12 +169,12 @@ Bugfixes & features by * [Jos Hanon](https://github.com/Josha) * [Bertrand Lemasle](https://github.com/blemasle) * [Mikael Falkvidd](https://github.com/mfalkvidd) -* [Rowan Goemans] (https://github.com/rowanG077) -* [Nils Bokermann] (https://github.com/sanddorn) -* [Florian] (https://github.com/1technophile) -* [wrong-kendall] (https://github.com/wrong-kendall) -* [bitli] (https://github.com/bitli) -* [ChristianBauerAMDC] (https://github.com/bitli) +* [Rowan Goemans](https://github.com/rowanG077) +* [Nils Bokermann](https://github.com/sanddorn) +* [Florian](https://github.com/1technophile) +* [wrong-kendall](https://github.com/wrong-kendall) +* [bitli](https://github.com/bitli) +* [ChristianBauerAMDC](https://github.com/bitli) ======= * [bitli] (https://github.com/bitli) From 28db4014af38b8f79c1edcbd93f5c25128cfb036 Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Sun, 23 May 2021 16:29:46 +0200 Subject: [PATCH 16/32] Fix printable object Explanation printable object in README.md --- ArduinoLog.cpp | 8 ++++++-- ArduinoLog.h | 2 +- README.md | 15 ++++++++++++--- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/ArduinoLog.cpp b/ArduinoLog.cpp index dcbc257..309f3ac 100644 --- a/ArduinoLog.cpp +++ b/ArduinoLog.cpp @@ -202,10 +202,14 @@ void Logging::printFormat(const char format, va_list *args) { if (h<0xF ) _logOutput->print('0'); _logOutput->print(h,HEX); } + else if (format == 'p') + { + register Printable *obj = (Printable *) va_arg(*args, int); + _logOutput->print(*obj); + } else if (format == 'b') { _logOutput->print(va_arg(*args, int), BIN); - return; } else if (format == 'B') { @@ -233,7 +237,7 @@ void Logging::printFormat(const char format, va_list *args) { if (c<0xF) _logOutput->print('0'); _logOutput->print(c, HEX); } - } + } else if(format == 't') { if (va_arg(*args, int) == 1) diff --git a/ArduinoLog.h b/ArduinoLog.h index acb379e..a22c575 100644 --- a/ArduinoLog.h +++ b/ArduinoLog.h @@ -310,7 +310,7 @@ class Logging void print(const __FlashStringHelper *format, va_list args); - void print(const Printable& obj, va_list& args) + void print(const Printable& obj, va_list args) { _logOutput->print(obj); } diff --git a/README.md b/README.md index 61fb8e5..cb10d9f 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ This package has been published to the Arduino & PlatformIO package managers, bu Log.warning (F("Log as Warning with integer values from Flash : %d, %d"CR) , 34 , 799870); ``` -[See examples/Log/Log.ino](examples/Log/Log.ino) +See [examples/Log/Log.ino](examples/Log/Log.ino) ## Usage @@ -114,9 +114,20 @@ where the format string can be used to format the log variables * %t display as boolean value "t" or "f" * %T display as boolean value "true" or "false" * %D,%F display as double value +* %p display a printable object. ``` Newlines can be added using the CR keyword or by using the `...ln` version of each of the log functions. The difference when using the `...ln` is that the newline is placed after suffix, and only a single newline can be added. + +### Displaying a printable object + +Some Arduino objects are printable. That is, they implement the `Printable` interface and are able for format their own representation +As an example, the IPadress object is printable: + +```c++ + IPAddress ipAddress(192, 168, 0, 1); + Log.verboseln ("ip address : %p", ipAddress); +``` ### Storing messages in Flash memory @@ -175,8 +186,6 @@ Bugfixes & features by * [wrong-kendall](https://github.com/wrong-kendall) * [bitli](https://github.com/bitli) * [ChristianBauerAMDC](https://github.com/bitli) -======= -* [bitli] (https://github.com/bitli) ## On using and modifying libraries From 92aa6be4e47aba8e2660c2474e199a18d1274248 Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Sun, 23 May 2021 16:43:59 +0200 Subject: [PATCH 17/32] Updated manual --- README.md | 54 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index cb10d9f..92f2ebd 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ The loglevels available are example ``` - Log.begin(LOG_LEVEL_ERROR, &Serial, true); +Log.begin(LOG_LEVEL_ERROR, &Serial, true); ``` if you want to fully remove all logging code, uncomment `#define DISABLE_LOGGING` in `ArduinoLog.h`, this may significantly reduce your sketch/library size. @@ -119,14 +119,35 @@ where the format string can be used to format the log variables Newlines can be added using the CR keyword or by using the `...ln` version of each of the log functions. The difference when using the `...ln` is that the newline is placed after suffix, and only a single newline can be added. +### Examples + +```c++ +Log.fatal (F("Log as Fatal with string value from Flash : %s"CR ) , "value" ); +Log.errorln ( "Log as Error with binary values : %b, %B" , 23 , 345808); +Log.warning (F("Log as Warning with integer values from Flash : %d, %d"CR) , 34 , 799870); +Log.notice ( "Log as Notice with hexadecimal values : %x, %X"CR , 21 , 348972); +Log.trace ( "Log as Trace with Flash string : %S"CR ) , F("value") ); +Log.verboseln (F("Log as Verbose with bool value from Flash : %t, %T" ) , true, false ); +``` + +### Disable library + +(if your code is completely tested) all logging code can be compiled out. Do this by uncommenting +```c++ +#define DISABLE_LOGGING +``` +in `Logging.h`. This may significantly reduce your project size. + +## Advanced usage + ### Displaying a printable object Some Arduino objects are printable. That is, they implement the `Printable` interface and are able for format their own representation As an example, the IPadress object is printable: ```c++ - IPAddress ipAddress(192, 168, 0, 1); - Log.verboseln ("ip address : %p", ipAddress); +IPAddress ipAddress(192, 168, 0, 1); +Log.verboseln ("ip address : %p", ipAddress); ``` ### Storing messages in Flash memory @@ -134,9 +155,9 @@ As an example, the IPadress object is printable: Flash strings log variables can be stored and reused at several places to reduce final hex size. ```c++ - const __FlashStringHelper * logAs = F("Log as"); - Log.fatal (F("%S Fatal with string value from Flash : %s"CR ) , logAs, "value" ); - Log.error ( "%S Error with binary values : %b, %B"CR , logAs, 23 , 345808); +const __FlashStringHelper * logAs = F("Log as"); +Log.fatal (F("%S Fatal with string value from Flash : %s"CR ) , logAs, "value" ); +Log.error ( "%S Error with binary values : %b, %B"CR , logAs, 23 , 345808); ``` If you want to declare that string globally (outside of a function), you will need to use the PROGMEM macro instead. @@ -149,25 +170,6 @@ void logError() { } ``` -### Examples - -```c++ - Log.fatal (F("Log as Fatal with string value from Flash : %s"CR ) , "value" ); - Log.errorln ( "Log as Error with binary values : %b, %B" , 23 , 345808); - Log.warning (F("Log as Warning with integer values from Flash : %d, %d"CR) , 34 , 799870); - Log.notice ( "Log as Notice with hexadecimal values : %x, %X"CR , 21 , 348972); - Log.trace ( "Log as Trace with Flash string : %S"CR ) , F("value") ); - Log.verboseln (F("Log as Verbose with bool value from Flash : %t, %T" ) , true, false ); -``` - -### Disable library - -(if your code is completely tested) all logging code can be compiled out. Do this by uncommenting -```c++ -#define DISABLE_LOGGING -``` -in `Logging.h`. This may significantly reduce your project size. - ## Credit Based on library by @@ -185,7 +187,7 @@ Bugfixes & features by * [Florian](https://github.com/1technophile) * [wrong-kendall](https://github.com/wrong-kendall) * [bitli](https://github.com/bitli) -* [ChristianBauerAMDC](https://github.com/bitli) +* [ChristianBauerAMDC](https://github.com/ChristianBauerAMDC) ## On using and modifying libraries From 9a0fd06eae858a35345c1c80b8059b09927df095 Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Sun, 23 May 2021 16:44:58 +0200 Subject: [PATCH 18/32] spacing --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 92f2ebd..d6a3cb0 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ This package has been published to the Arduino & PlatformIO package managers, bu See [examples/Log/Log.ino](examples/Log/Log.ino) + ## Usage ### Initialisation @@ -138,6 +139,7 @@ Log.verboseln (F("Log as Verbose with bool value from Flash : %t, %T" ) , t ``` in `Logging.h`. This may significantly reduce your project size. + ## Advanced usage ### Displaying a printable object @@ -170,6 +172,7 @@ void logError() { } ``` + ## Credit Based on library by From ff0edc9587bef3de25623efc71f9599884b56462 Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Mon, 24 May 2021 00:20:40 +0200 Subject: [PATCH 19/32] Slightly breaking change - suffix & Prefix now pass log level Added advanced example --- ArduinoLog.h | 12 ++-- README.md | 23 +++--- examples/Log-advanced/Log-advanced.ino | 97 ++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 13 deletions(-) create mode 100644 examples/Log-advanced/Log-advanced.ino diff --git a/ArduinoLog.h b/ArduinoLog.h index a22c575..04557f1 100644 --- a/ArduinoLog.h +++ b/ArduinoLog.h @@ -29,7 +29,7 @@ Licensed under the MIT License . #define PSTR(str) (str) #define F(string_literal) (reinterpret_cast(PSTR(string_literal))) #endif -typedef void (*printfunction)(Print*); +typedef void (*printfunction)(Print*, int); // ************************************************************************* @@ -41,6 +41,7 @@ typedef void (*printfunction)(Print*); #define LOG_LEVEL_FATAL 1 #define LOG_LEVEL_ERROR 2 #define LOG_LEVEL_WARNING 3 +#define LOG_LEVEL_INFO 4 #define LOG_LEVEL_NOTICE 4 #define LOG_LEVEL_TRACE 5 #define LOG_LEVEL_VERBOSE 6 @@ -79,7 +80,8 @@ typedef void (*printfunction)(Print*); * 1 - LOG_LEVEL_FATAL fatal errors * 2 - LOG_LEVEL_ERROR all errors * 3 - LOG_LEVEL_WARNING errors and warnings - * 4 - LOG_LEVEL_NOTICE errors, warnings and notices + * 4 - LOG_LEVEL_INFO errors, warnings and notices + * 4 - LOG_LEVEL_NOTICE Same as INFO, kept for backward compatibility * 5 - LOG_LEVEL_TRACE errors, warnings, notices, traces * 6 - LOG_LEVEL_VERBOSE all */ @@ -332,11 +334,11 @@ class Logging if (_prefix != NULL) { - _prefix(_logOutput); + _prefix(_logOutput, level); } if (_showLevel) { - static const char levels[] = "FEWNTV"; + static const char levels[] = "FEWITV"; _logOutput->print(levels[level - 1]); _logOutput->print(": "); } @@ -347,7 +349,7 @@ class Logging if(_suffix != NULL) { - _suffix(_logOutput); + _suffix(_logOutput, level); } if (cr) { diff --git a/README.md b/README.md index d6a3cb0..b42afd0 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ArduinoLog - C++ Log library for Arduino devices [![Build Status](https://travis-ci.org/thijse/Arduino-Log.svg?branch=master)](https://travis-ci.org/thijse/Arduino-Log) [![License](https://img.shields.io/badge/license-MIT%20License-blue.svg)](http://doge.mit-license.org) -*An minimalistic Logging framework for Arduino-compatible embedded systems.* +*An minimalistic Logging framework for Arduino-compatible embedded systems.* ArduinoLog is a minimalistic framework to help the programmer output log statements to an output of choice, fashioned after extensive logging libraries such as log4cpp ,log4j and log4net. In case of problems with an application, it is helpful to enable logging so that the problem can be located. ArduinoLog is designed so that log statements can remain in the code with minimal performance cost. In order to facilitate this the loglevel can be adjusted, and (if your code is completely tested) all logging code can be compiled out. @@ -110,12 +110,12 @@ where the format string can be used to format the log variables * %u display as unsigned long value * %x display as hexadecimal value * %X display as hexadecimal value prefixed by `0x` and leading zeros -* %b display as binary number -* %B display as binary number, prefixed by `0b` +* %b display as binary number +* %B display as binary number, prefixed by `0b` * %t display as boolean value "t" or "f" * %T display as boolean value "true" or "false" * %D,%F display as double value -* %p display a printable object. +* %p display a printable object ``` Newlines can be added using the CR keyword or by using the `...ln` version of each of the log functions. The difference when using the `...ln` is that the newline is placed after suffix, and only a single newline can be added. @@ -151,15 +151,17 @@ As an example, the IPadress object is printable: IPAddress ipAddress(192, 168, 0, 1); Log.verboseln ("ip address : %p", ipAddress); ``` + +[this example](https://forum.arduino.cc/t/printable-classes/438816) shows how to your own classes printable -### Storing messages in Flash memory + ### Storing messages in Flash memory Flash strings log variables can be stored and reused at several places to reduce final hex size. ```c++ const __FlashStringHelper * logAs = F("Log as"); -Log.fatal (F("%S Fatal with string value from Flash : %s"CR ) , logAs, "value" ); -Log.error ( "%S Error with binary values : %b, %B"CR , logAs, 23 , 345808); +Log.fatal (F("%S Fatal with string value from Flash : %s"CR ) , logAs, "value" ); +Log.error ( "%S Error with binary values : %b, %B"CR , logAs, 23 , 345808); ``` If you want to declare that string globally (outside of a function), you will need to use the PROGMEM macro instead. @@ -172,6 +174,11 @@ void logError() { } ``` +### Custom logging format + +You can modify your logging format by defining a custom prefix & suffix for each log line + + ## Credit @@ -199,4 +206,4 @@ Bugfixes & features by ## Copyright -ArduinoLog is provided Copyright © 2017,2018, 2019, 2021 under MIT License. +ArduinoLog Copyright © 2017,2018, 2019, 2021 is provided under MIT License. diff --git a/examples/Log-advanced/Log-advanced.ino b/examples/Log-advanced/Log-advanced.ino new file mode 100644 index 0000000..bf54b4f --- /dev/null +++ b/examples/Log-advanced/Log-advanced.ino @@ -0,0 +1,97 @@ +#include +#include + + +/* + _ ___ ___ _ _ ___ _ _ ___ _ ___ ___ + /_\ | _ \ \| | | |_ _| \| |/ _ \| | / _ \ / __| + / _ \| / |) | |_| || || .` | (_) | |_| (_) | (_ | + /_/ \_\_|_\___/ \___/|___|_|\_|\___/|____\___/ \___| + + Log library example showing several advanced features + Licensed under the MIT License . + + This example sketch shows most of the features of the ArduinoLog library + +*/ + +const char * charArray = "this is a string"; +const char flashCharArray1[] PROGMEM = "this is a string"; +String stringValue1 = "this is a string"; +IPAddress ipAdress(192, 168, 0, 1); + +void setup() { + // Set up serial port and wait until connected + Serial.begin(9600); + while(!Serial && !Serial.available()){} + + + Log.setPrefix(printPrefix); // set prefix similar to NLog + Log.setSuffix(printSuffix); // set suffix + Log.begin(LOG_LEVEL_VERBOSE, &Serial); + Log.setShowLevel(false); // Do not show loglevel, we will do this in the prefix +} + +void loop() { + // set up some random variables + + + //__FlashStringHelper cannot be declared outside a function + const __FlashStringHelper * flashCharArray2 = F("this is a string"); + + Log.notice ( "Log global Flash string value : %S" CR, flashCharArray1 ); + Log.traceln ( "Log local Flash string value : %S" CR, flashCharArray2 ); + Log.notice ( "Log string value : %s" CR, stringValue1.c_str()); + Log.verboseln (F("Log ip adress : %p") , ipAdress ); + + delay(5000); +} + +void printPrefix(Print* _logOutput, int logLevel) { + printTimestamp(_logOutput); + printLogLevel (_logOutput, logLevel); +} + +void printTimestamp(Print* _logOutput) { + + // Division constants + const unsigned long MSECS_PER_SEC = 1000; + const unsigned long SECS_PER_MIN = 60; + const unsigned long SECS_PER_HOUR = 3600; + const unsigned long SECS_PER_DAY = 86400; + + // Total time + const unsigned long msecs = millis() ; + const unsigned long secs = msecs / MSECS_PER_SEC; + + // Time in components + const unsigned long MiliSeconds = msecs % MSECS_PER_SEC; + const unsigned long Seconds = secs % SECS_PER_MIN ; + const unsigned long Minutes = (secs / SECS_PER_MIN) % SECS_PER_MIN; + const unsigned long Hours = (secs % SECS_PER_DAY) / SECS_PER_HOUR; + + // Time as string + char timestamp[20]; + sprintf(timestamp, "%02d:%02d:%02d.%03d ", Hours, Minutes, Seconds, MiliSeconds); + _logOutput->print(timestamp); +} + + +void printLogLevel(Print* _logOutput, int logLevel) { + /// Show log description based on log level + switch (logLevel) + { + default: + case 0:_logOutput->print("SILENT " ); break; + case 1:_logOutput->print("FATAL " ); break; + case 2:_logOutput->print("ERROR " ); break; + case 3:_logOutput->print("WARNING "); break; + case 4:_logOutput->print("INFO " ); break; + case 5:_logOutput->print("TRACE " ); break; + case 6:_logOutput->print("VERBOSE "); break; + } +} + +void printSuffix(Print* _logOutput, int logLevel) { + _logOutput->print(""); +} From dd2a1030dba8d497624b6157e9adf558a4f7653f Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Mon, 24 May 2021 00:34:26 +0200 Subject: [PATCH 20/32] Updated advanced example README.md --- README.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b42afd0..2a6ae36 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,8 @@ in `Logging.h`. This may significantly reduce your project size. ## Advanced usage +Advanced features are demonstrated in example [examples/Log-advanced/Log-advanced.ino](examples/Log-advanced/Log-advanced.ino) + ### Displaying a printable object Some Arduino objects are printable. That is, they implement the `Printable` interface and are able for format their own representation @@ -176,9 +178,19 @@ void logError() { ### Custom logging format -You can modify your logging format by defining a custom prefix & suffix for each log line - +You can modify your logging format by defining a custom prefix & suffix for each log line. For example: +```c++ +void printPrefix(Print* _logOutput, int logLevel) { + printTimestamp(_logOutput); + printLogLevel (_logOutput, logLevel); +} +``` +will result in log timestamps very similar to e.g. NLOG: +``` +00:47:51.432 VERBOSE Log with suffix & prefix +``` +See ## Credit @@ -206,4 +218,4 @@ Bugfixes & features by ## Copyright -ArduinoLog Copyright © 2017,2018, 2019, 2021 is provided under MIT License. +ArduinoLog (Copyright © 2017,2018, 2019, 2021) is provided under MIT License. From 043a172903064179cd50c6740840aed3e5ff60ed Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Mon, 24 May 2021 12:13:30 +0200 Subject: [PATCH 21/32] Upgraded to version 1.1.1, because of minor interface change Renamed basic example Updated & cleaned up examples --- ArduinoLog.cpp | 2 +- ArduinoLog.h | 14 +- README.md | 8 +- examples/Log-advanced/Log-advanced.ino | 3 - .../{Log/Log.ino => Log-basic/Log-basic.ino} | 197 ++++++++---------- keywords.txt | 3 + library.json | 4 +- library.properties | 4 +- 8 files changed, 113 insertions(+), 122 deletions(-) rename examples/{Log/Log.ino => Log-basic/Log-basic.ino} (80%) diff --git a/ArduinoLog.cpp b/ArduinoLog.cpp index 309f3ac..2f06cfa 100644 --- a/ArduinoLog.cpp +++ b/ArduinoLog.cpp @@ -5,7 +5,7 @@ /_/ \_\_|_\___/ \___/|___|_|\_|\___/|____\___/ \___| Log library for Arduino - version 1.0.4 + version 1.1.1 https://github.com/thijse/Arduino-Log Licensed under the MIT License . diff --git a/ArduinoLog.h b/ArduinoLog.h index 04557f1..efb20f7 100644 --- a/ArduinoLog.h +++ b/ArduinoLog.h @@ -5,7 +5,7 @@ /_/ \_\_|_\___/ \___/|___|_|\_|\___/|____\___/ \___| Log library for Arduino - version 1.0.4 + version 1.1.1 https://github.com/thijse/Arduino-Log Licensed under the MIT License . @@ -263,6 +263,18 @@ class Logging #endif } + template void info(T msg, Args...args) { +#ifndef DISABLE_LOGGING + printLevel(LOG_LEVEL_INFO, false, msg, args...); +#endif + } + + template void infoln(T msg, Args...args) { +#ifndef DISABLE_LOGGING + printLevel(LOG_LEVEL_INFO, true, msg, args...); +#endif + } + /** * Output a trace message. Output message contains * N: followed by original message diff --git a/README.md b/README.md index 2a6ae36..c856445 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ This package has been published to the Arduino & PlatformIO package managers, bu Log.warning (F("Log as Warning with integer values from Flash : %d, %d"CR) , 34 , 799870); ``` -See [examples/Log/Log.ino](examples/Log/Log.ino) +See [Log-basic.ino](examples/Log-basic/Log-basic.ino) example ## Usage @@ -142,7 +142,7 @@ in `Logging.h`. This may significantly reduce your project size. ## Advanced usage -Advanced features are demonstrated in example [examples/Log-advanced/Log-advanced.ino](examples/Log-advanced/Log-advanced.ino) +Advanced features are demonstrated in [Log-advanced](examples/Log-advanced/Log-advanced.ino) example. ### Displaying a printable object @@ -187,11 +187,9 @@ void printPrefix(Print* _logOutput, int logLevel) { ``` will result in log timestamps very similar to e.g. NLOG: ``` -00:47:51.432 VERBOSE Log with suffix & prefix +00:47:51.432 VERBOSE Message to be logged ``` -See - ## Credit Based on library by diff --git a/examples/Log-advanced/Log-advanced.ino b/examples/Log-advanced/Log-advanced.ino index bf54b4f..d40256d 100644 --- a/examples/Log-advanced/Log-advanced.ino +++ b/examples/Log-advanced/Log-advanced.ino @@ -1,7 +1,5 @@ #include #include - - /* _ ___ ___ _ _ ___ _ _ ___ _ ___ ___ /_\ | _ \ \| | | |_ _| \| |/ _ \| | / _ \ / __| @@ -35,7 +33,6 @@ void setup() { void loop() { // set up some random variables - //__FlashStringHelper cannot be declared outside a function const __FlashStringHelper * flashCharArray2 = F("this is a string"); diff --git a/examples/Log/Log.ino b/examples/Log-basic/Log-basic.ino similarity index 80% rename from examples/Log/Log.ino rename to examples/Log-basic/Log-basic.ino index bd638a0..181292b 100644 --- a/examples/Log/Log.ino +++ b/examples/Log-basic/Log-basic.ino @@ -1,109 +1,90 @@ -#include -/* - _ ___ ___ _ _ ___ _ _ ___ _ ___ ___ - /_\ | _ \ \| | | |_ _| \| |/ _ \| | / _ \ / __| - / _ \| / |) | |_| || || .` | (_) | |_| (_) | (_ | - /_/ \_\_|_\___/ \___/|___|_|\_|\___/|____\___/ \___| - - Log library example - Licensed under the MIT License . - - This example sketch shows most of the features of the ArduinoLog library - -*/ - - -int intValue1 , intValue2; -long longValue1, longValue2; -bool boolValue1, boolValue2; -const char charNotPrintable = 0x8B; -const char * charArray = "this is a string"; -const char flashCharArray1[] PROGMEM = "this is a string"; -String stringValue1 = "this is a string"; -float floatValue; -double doubleValue; - -void setup() { - // Set up serial port and wait until connected - Serial.begin(9600); - while(!Serial && !Serial.available()){} - randomSeed(analogRead(0)); - // Pass log level, whether to show log level, and print interface. - // Available levels are: - // LOG_LEVEL_SILENT, LOG_LEVEL_FATAL, LOG_LEVEL_ERROR, LOG_LEVEL_WARNING, LOG_LEVEL_NOTICE, LOG_LEVEL_TRACE, LOG_LEVEL_VERBOSE - // Note: if you want to fully remove all logging code, uncomment #define DISABLE_LOGGING in Logging.h - // this will significantly reduce your project size - - Log.begin(LOG_LEVEL_VERBOSE, &Serial); - - - //Start logging - - Log.notice(F(CR "******************************************" CR)); // Info string with Newline - Log.notice( "*** Logging example " CR); // Info string in flash memory - Log.notice(F("******************* ")); Log.notice("*********************** " CR); // two info strings without newline -} - -void loop() { - // set up some random variables - intValue1 = random(100); - intValue2 = random(10000); - longValue1 = random(1000000); - longValue2 = random(100000000); - boolValue1 = random(2)==0; - boolValue2 = random(2)==1; - floatValue = 12.34; - doubleValue= 1234.56789; - - //__FlashStringHelper cannot be declared outside a function - const __FlashStringHelper * flashCharArray2 = F("this is a string"); - - Log.notice ( "Log as Info with integer values : %d, %d" CR , intValue1, intValue2); - Log.notice (F("Log as Info with hex values : %x, %X" CR ), intValue1, intValue1); - Log.notice ( "Log as Info with hex values : %x, %X" CR , intValue2, intValue2); - Log.notice (F("Log as Info with binary values : %b, %B" CR ), intValue1, intValue1); - Log.notice ( "Log as Info with binary values : %b, %B" CR , intValue2, intValue2); - Log.notice (F("Log as Info with long values : %l, %l" CR ), longValue1, longValue2); - Log.notice ( "Log as Info with bool values : %t, %T" CR , boolValue1, boolValue2); - Log.notice (F("Log as Info with char value : %c" CR ), charArray[0]); - Log.notice ( "Log as Info with char value : %C" CR , charNotPrintable); - Log.notice (F("Log as Info with string value : %s" CR ), charArray); - Log.notice ( "Log as Info with Flash string value : %S" CR , flashCharArray1); - Log.notice ( "Log as Info with Flash string value : %S" CR , flashCharArray2); - Log.notice ( "Log as Info with string value : %s" CR , stringValue1.c_str()); - Log.notice (F("Log as Info with float value : %F" CR ), floatValue); - Log.notice ( "Log as Info with float value : %F" CR , floatValue); - Log.notice (F("Log as Info with double value : %D" CR ), doubleValue); - Log.notice ( "Log as Info with double value : %D" CR , doubleValue); - Log.notice (F("Log as Debug with mixed values : %d, %d, %l, %l, %t, %T" CR ), intValue1 , intValue2, - longValue1, longValue2, boolValue1, boolValue2); - - Log.trace ( "Log as Trace with bool value : %T" CR , boolValue1); - Log.traceln ( "Log as Trace with bool value : %T" , boolValue1); - Log.warning ( "Log as Warning with bool value : %T" CR , boolValue1); - Log.warningln( "Log as Warning with bool value : %T" , boolValue1); - Log.error ( "Log as Error with bool value : %T" CR , boolValue1); - Log.errorln ( "Log as Error with bool value : %T" , boolValue1); - Log.fatal ( "Log as Fatal with bool value : %T" CR , boolValue1); - Log.fatalln ( "Log as Fatal with bool value : %T" , boolValue1); - Log.verboseln(F("Log as Verbose with bool value : %T" ), boolValue2); - Log.verbose (F("Log as Verbose with bool value : %T" CR ), boolValue2); - - Log.setPrefix(printTimestamp); // set timestamp as prefix - Log.setSuffix(printCarret); // set carret as suffix - Log.verboseln(F("Log with suffix & prefix")); - Log.setPrefix(NULL); // set timestamp as prefix - Log.setSuffix(NULL); // set carret as suffix - - delay(5000); -} - -void printTimestamp(Print* _logOutput) { - char c[12]; - int m = sprintf(c, "%10lu ", millis()); - _logOutput->print(c); -} - -void printCarret(Print* _logOutput) { - _logOutput->print('>'); +#include +/* + _ ___ ___ _ _ ___ _ _ ___ _ ___ ___ + /_\ | _ \ \| | | |_ _| \| |/ _ \| | / _ \ / __| + / _ \| / |) | |_| || || .` | (_) | |_| (_) | (_ | + /_/ \_\_|_\___/ \___/|___|_|\_|\___/|____\___/ \___| + + Log library basic example + Licensed under the MIT License . + + This example sketch shows most of the most used features of the ArduinoLog library + +*/ + +int intValue1 , intValue2; +long longValue1, longValue2; +bool boolValue1, boolValue2; +const char charNotPrintable = 0x8B; +const char * charArray = "this is a string"; +const char flashCharArray1[] PROGMEM = "this is a string"; +String stringValue1 = "this is a string"; +float floatValue; +double doubleValue; + +void setup() { + // Set up serial port and wait until connected + Serial.begin(9600); + while(!Serial && !Serial.available()){} + randomSeed(analogRead(0)); + // Pass log level, whether to show log level, and print interface. + // Available levels are: + // LOG_LEVEL_SILENT, LOG_LEVEL_FATAL, LOG_LEVEL_ERROR, LOG_LEVEL_WARNING, LOG_LEVEL_INFO, LOG_LEVEL_TRACE, LOG_LEVEL_VERBOSE + // Note: if you want to fully remove all logging code, uncomment #define DISABLE_LOGGING in Logging.h + // this will significantly reduce your project size + + Log.begin(LOG_LEVEL_VERBOSE, &Serial); + + + //Start logging + + Log.notice(F(CR "******************************************" CR)); // Info string with Newline + Log.notice( "*** Logging example " CR); // Info string in flash memory + Log.notice(F("******************* ")); Log.notice("*********************** " CR); // two info strings without newline will end up on same line +} + +void loop() { + // set up some random variables + intValue1 = random(100); + intValue2 = random(10000); + longValue1 = random(1000000); + longValue2 = random(100000000); + boolValue1 = random(2)==0; + boolValue2 = random(2)==1; + floatValue = 12.34; + doubleValue= 1234.56789; + + + Log.notice ( "Log as Info with integer values : %d, %d" CR , intValue1, intValue2); + Log.notice (F("Log as Info with hex values : %x, %X" CR ), intValue1, intValue1); + Log.notice ( "Log as Info with hex values : %x, %X" CR , intValue2, intValue2); + Log.notice (F("Log as Info with binary values : %b, %B" CR ), intValue1, intValue1); + Log.notice ( "Log as Info with binary values : %b, %B" CR , intValue2, intValue2); + Log.notice (F("Log as Info with long values : %l, %l" CR ), longValue1, longValue2); + Log.notice ( "Log as Info with bool values : %t, %T" CR , boolValue1, boolValue2); + Log.notice (F("Log as Info with char value : %c" CR ), charArray[0]); + Log.notice ( "Log as Info with char value : %C" CR , charNotPrintable); + Log.notice (F("Log as Info with string value : %s" CR ), charArray); + Log.notice ( "Log as Info with Flash string value : %S" CR , flashCharArray1); + Log.notice ( "Log as Info with string value : %s" CR , stringValue1.c_str()); + Log.notice (F("Log as Info with float value : %F" CR ), floatValue); + Log.notice ( "Log as Info with float value : %F" CR , floatValue); + Log.notice (F("Log as Info with double value : %D" CR ), doubleValue); + Log.notice ( "Log as Info with double value : %D" CR , doubleValue); + Log.notice (F("Log as Debug with mixed values : %d, %d, %l, %l, %t, %T" CR ), intValue1 , intValue2 , + longValue1, longValue2, + boolValue1, boolValue2); + Log.trace ( "Log as Trace with bool value : %T" CR , boolValue1); + Log.traceln ( "Log as Trace with bool value : %T" , boolValue1); + Log.warning ( "Log as Warning with bool value : %T" CR , boolValue1); + Log.warningln( "Log as Warning with bool value : %T" , boolValue1); + Log.error ( "Log as Error with bool value : %T" CR , boolValue1); + Log.errorln ( "Log as Error with bool value : %T" , boolValue1); + Log.fatal ( "Log as Fatal with bool value : %T" CR , boolValue1); + Log.fatalln ( "Log as Fatal with bool value : %T" , boolValue1); + Log.verboseln(F("Log as Verbose with bool value : %T" ), boolValue2); + Log.verbose (F("Log as Verbose with bool value : %T" CR ), boolValue2); + + + delay(5000); } \ No newline at end of file diff --git a/keywords.txt b/keywords.txt index 2287ce6..9204507 100644 --- a/keywords.txt +++ b/keywords.txt @@ -20,6 +20,8 @@ error KEYWORD2 errorln KEYWORD2 warning KEYWORD2 warningln KEYWORD2 +info KEYWORD2 +infoln KEYWORD2 notice KEYWORD2 noticeln KEYWORD2 trace KEYWORD2 @@ -50,6 +52,7 @@ LOG_LEVEL_FATAL LITERAL1 Constants LOG_LEVEL_ERROR LITERAL1 Constants LOG_LEVEL_WARNING LITERAL1 Constants LOG_LEVEL_NOTICE LITERAL1 Constants +LOG_LEVEL_INFO LITERAL1 Constants LOG_LEVEL_TRACE LITERAL1 Constants LOG_LEVEL_VERBOSE LITERAL1 Constants diff --git a/library.json b/library.json index 709a31b..2afeaac 100644 --- a/library.json +++ b/library.json @@ -1,8 +1,8 @@ { "name": "ArduinoLog", "keywords": "logging, debug, log, log levels, AVR, ESP8266", - "description": "ArduinoLog is a minimalistic logging framework to help the programmer output log statements to a chosen output target. ArduinoLog is designed so that log statements can remain in the code with minimal performance cost. In order to facilitate this the loglevel can be adjusted, and if the code is completely tested all logging code can be compiled out. Tested for AVR and ESP8266 boards.", - "version": "1.0.4", + "description": "ArduinoLog is a minimalistic logging framework to help the programmer output log statements to a variety of output targets. ArduinoLog is designed so that log statements can remain in the code with minimal performance cost. In order to facilitate this the loglevel can be adjusted, and if the code is completely tested all logging code can be compiled out. Tested for AVR, ESP8266 & ESP32 boards. Detailed instructions for use on Github page.", + "version": "1.1.1", "authors": { "name": "Thijs Elenbaas", "url": "https://github.com/thijse", diff --git a/library.properties b/library.properties index 8c9861f..1279f4a 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ name=ArduinoLog -version=1.0.4 +version=1.1.1 author=Thijs Elenbaas maintainer=Thijs Elenbaas sentence=Small logging framework -paragraph=ArduinoLog is a minimalistic logging framework to help the programmer output log statements to a variety of output targets. ArduinoLog is designed so that log statements can remain in the code with minimal performance cost. In order to facilitate this the loglevel can be adjusted, and if the code is completely tested all logging code can be compiled out. Tested for AVR and ESP8266 boards. +paragraph=ArduinoLog is a minimalistic logging framework to help the programmer output log statements to a variety of output targets. ArduinoLog is designed so that log statements can remain in the code with minimal performance cost. In order to facilitate this the loglevel can be adjusted, and if the code is completely tested all logging code can be compiled out. Tested for AVR, ESP8266 & ESP32 boards. Detailed instructions for use on Github page. category=Communication url=https://github.com/thijse/Arduino-Log/ architectures=* From ef41df45a559f8a1259c82fc73fca4f65c79eb23 Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Mon, 24 May 2021 12:16:41 +0200 Subject: [PATCH 22/32] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c856445..ce012db 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,7 @@ IPAddress ipAddress(192, 168, 0, 1); Log.verboseln ("ip address : %p", ipAddress); ``` -[this example](https://forum.arduino.cc/t/printable-classes/438816) shows how to your own classes printable +[this example](https://forum.arduino.cc/t/printable-classes/438816) shows how to make your own classes printable ### Storing messages in Flash memory From 538ea9702ebbfff049f6364e882ec52bee695bb3 Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Mon, 24 May 2021 12:51:22 +0200 Subject: [PATCH 23/32] - Added both examples to Travis test setup --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 167bd7b..fadfc49 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,14 +15,16 @@ "sudo cp -r arduino-1.6.13 /usr/local/share/arduino", "sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino", "sudo ln -s $PWD /usr/local/share/arduino/libraries/ArduinoLog", - "arduino --verify --board arduino:avr:uno $PWD/examples/Log/Log.ino", + "arduino --verify --board arduino:avr:uno $PWD/examples/Log-basic/Log-basic.ino" + "arduino --verify --board arduino:avr:uno $PWD/examples/Log-advanced/Log-advanced.ino" "sudo rm -rf /usr/local/share/arduino", "sudo cp -r arduino-1.8.1 /usr/local/share/arduino", "sudo rm /usr/local/bin/arduino", "sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino", "sudo ln -s $PWD /usr/local/share/arduino/libraries/ArduinoLog", - "arduino --verify --board arduino:avr:uno $PWD/examples/Log/Log.ino" + "arduino --verify --board arduino:avr:uno $PWD/examples/Log-basic/Log-basic.ino" + "arduino --verify --board arduino:avr:uno $PWD/examples/Log-advanced/Log-advanced.ino" ], "group": "stable", "dist": "precise", From aa0831ad50f786e40d8d23e9265c4725406d176f Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Mon, 24 May 2021 12:54:24 +0200 Subject: [PATCH 24/32] Updated Travis build instructions for new examples --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fadfc49..992647a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,4 +29,4 @@ "group": "stable", "dist": "precise", "os": "linux" -} +} \ No newline at end of file From c88403e2f47f13f1737326322e49b6492199c0c5 Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Mon, 24 May 2021 20:01:57 +0200 Subject: [PATCH 25/32] Update documentation in ArduinoLog.h --- ArduinoLog.h | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/ArduinoLog.h b/ArduinoLog.h index efb20f7..348b536 100644 --- a/ArduinoLog.h +++ b/ArduinoLog.h @@ -50,29 +50,29 @@ typedef void (*printfunction)(Print*, int); #define LOGGING_VERSION 1_0_4 /** - * Logging is a helper class to output informations over - * RS232. If you know log4j or log4net, this logging class - * is more or less similar ;-)
- * Different loglevels can be used to extend or reduce output - * All methods are able to handle any number of output parameters. - * All methods print out a formated string (like printf).
- * To reduce output and program size, reduce loglevel. - * - * Output format string can contain below wildcards. Every wildcard - * must be start with percent sign (\%) + * ArduinoLog is a minimalistic framework to help the programmer output log statements to an output of choice, + * fashioned after extensive logging libraries such as log4cpp ,log4j and log4net. In case of problems with an + * application, it is helpful to enable logging so that the problem can be located. ArduinoLog is designed so + * that log statements can remain in the code with minimal performance cost. In order to facilitate this the + * loglevel can be adjusted, and (if your code is completely tested) all logging code can be compiled out. * * ---- Wildcards * - * %s replace with an string (char*) - * %c replace with an character - * %d replace with an integer value - * %l replace with an long value - * %x replace and convert integer value into hex - * %X like %x but combine with 0x123AB - * %b replace and convert integer value into binary - * %B like %x but combine with 0b10100011 - * %t replace and convert boolean value into "t" or "f" - * %T like %t but convert into "true" or "false" + * %s display as string (char*) + * %S display as string from flash memory (__FlashStringHelper* or char[] PROGMEM) + * %c display as single character + * %C display as single character or as hexadecimal value (prefixed by `0x`) if not a printable character + * %d display as integer value + * %l display as long value + * %u display as unsigned long value + * %x display as hexadecimal value + * %X display as hexadecimal value prefixed by `0x` and leading zeros + * %b display as binary number + * %B display as binary number, prefixed by `0b` + * %t display as boolean value "t" or "f" + * %T display as boolean value "true" or "false" + * %D,%F display as double value + * %p display a printable object * * ---- Loglevels * From 158fd6157004cc139157f64ce83e179555e77008 Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Mon, 24 May 2021 20:23:29 +0200 Subject: [PATCH 26/32] Added NL & LF characters --- ArduinoLog.h | 2 ++ README.md | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ArduinoLog.h b/ArduinoLog.h index 348b536..33e7564 100644 --- a/ArduinoLog.h +++ b/ArduinoLog.h @@ -47,6 +47,8 @@ typedef void (*printfunction)(Print*, int); #define LOG_LEVEL_VERBOSE 6 #define CR "\n" +#define LF "\r" +#define NL "\n\r" #define LOGGING_VERSION 1_0_4 /** diff --git a/README.md b/README.md index ce012db..628cd76 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ where the format string can be used to format the log variables * %p display a printable object ``` - Newlines can be added using the CR keyword or by using the `...ln` version of each of the log functions. The difference when using the `...ln` is that the newline is placed after suffix, and only a single newline can be added. + Newlines can be added using the `CR` keyword or by using the `...ln` version of each of the log functions. The difference when using the `...ln` is that the newline is placed after suffix, and only a single newline can be added. Some terminals prefer `NL` (New line). ### Examples From fb8686dd772ab68b2fff2c4082a864d80b5c3e75 Mon Sep 17 00:00:00 2001 From: Thijs Elenbaas Date: Thu, 27 May 2021 22:16:37 +0200 Subject: [PATCH 27/32] Merge of @wrong-kendall "Create a PlatformIO example and unit test" & "Don't cast the va_arg for __FlashStringHelper* or char* because it crashes on x86" --- ArduinoLog.cpp | 4 +- examples/platformio-basic/platformio.ini | 37 ++ examples/platformio-basic/src/main.cpp | 121 +++++++ .../platformio-basic/test/test_native.cpp | 325 ++++++++++++++++++ 4 files changed, 485 insertions(+), 2 deletions(-) create mode 100644 examples/platformio-basic/platformio.ini create mode 100644 examples/platformio-basic/src/main.cpp create mode 100644 examples/platformio-basic/test/test_native.cpp diff --git a/ArduinoLog.cpp b/ArduinoLog.cpp index 2f06cfa..538ea3d 100644 --- a/ArduinoLog.cpp +++ b/ArduinoLog.cpp @@ -172,12 +172,12 @@ void Logging::printFormat(const char format, va_list *args) { } else if (format == 's') { - register char *s = (char *)va_arg(*args, int); + register char *s = va_arg(*args, char *); _logOutput->print(s); } else if (format == 'S') { - register __FlashStringHelper *s = (__FlashStringHelper *)va_arg(*args, int); + register __FlashStringHelper *s = va_arg(*args, __FlashStringHelper *); _logOutput->print(s); } else if (format == 'd' || format == 'i') diff --git a/examples/platformio-basic/platformio.ini b/examples/platformio-basic/platformio.ini new file mode 100644 index 0000000..4e8559a --- /dev/null +++ b/examples/platformio-basic/platformio.ini @@ -0,0 +1,37 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[platformio] +default_envs = adafruit_feather_m4 + +[env:adafruit_feather_m4] +platform = atmelsam +board = adafruit_feather_m4 +framework = arduino +lib_deps = + ; TODO(kendall): Remove if/when Arduino-Log is available through + ; PlatformIO's Library Manager + https://github.com/thijse/Arduino-Log.git +test_ignore = test_native + + +[env:native] +platform = native +build_flags = + ; TODO(kendall): Remove if/when + ; https://github.com/thijse/Arduino-Log/pull/13 is merged + -DARDUINO=101 +lib_compat_mode = off +lib_deps = + https://github.com/FabioBatSilva/ArduinoFake.git + ; TODO(kendall): Remove if/when Arduino-Log is available through + ; PlatformIO's Library Manager + https://github.com/thijse/Arduino-Log.git + diff --git a/examples/platformio-basic/src/main.cpp b/examples/platformio-basic/src/main.cpp new file mode 100644 index 0000000..0a87923 --- /dev/null +++ b/examples/platformio-basic/src/main.cpp @@ -0,0 +1,121 @@ +#ifndef UNIT_TEST +#include +#include +/* + _ ___ ___ _ _ ___ _ _ ___ _ ___ ___ + /_\ | _ \ \| | | |_ _| \| |/ _ \| | / _ \ / __| + / _ \| / |) | |_| || || .` | (_) | |_| (_) | (_ | + /_/ \_\_|_\___/ \___/|___|_|\_|\___/|____\___/ \___| + + Log library example + Licensed under the MIT License . + + This example sketch shows most of the features of the ArduinoLog library + +*/ + +int intValue1, intValue2; +long longValue1, longValue2; +bool boolValue1, boolValue2; +const char *charArray = "this is a string"; +const char flashCharArray1[] PROGMEM = "this is a string"; +String stringValue1 = "this is a string"; +float floatValue; +double doubleValue; + +void printTimestamp(Print *_logOutput) { + char c[12]; + int m = sprintf(c, "%10lu ", millis()); + _logOutput->print(c); +} + +void printCarret(Print *_logOutput) { _logOutput->print('>'); } + +void setup() { + // Set up serial port and wait until connected + Serial.begin(9600); + while (!Serial && !Serial.available()) { + } + randomSeed(analogRead(0)); + // Pass log level, whether to show log level, and print interface. + // Available levels are: + // LOG_LEVEL_SILENT, LOG_LEVEL_FATAL, LOG_LEVEL_ERROR, LOG_LEVEL_WARNING, + // LOG_LEVEL_NOTICE, LOG_LEVEL_TRACE, LOG_LEVEL_VERBOSE Note: if you want to + // fully remove all logging code, uncomment #define DISABLE_LOGGING in + // Logging.h + // this will significantly reduce your project size + + Log.begin(LOG_LEVEL_VERBOSE, &Serial); + + // Start logging + + Log.notice( + F(CR "******************************************" CR)); // Info string + // with Newline + Log.notice( + "*** Logging example " CR); // Info string in + // flash memory + Log.notice(F("******************* ")); + Log.notice("*********************** " CR); // two info strings without newline +} + +void loop() { + // set up some random variables + intValue1 = random(100); + intValue2 = random(10000); + longValue1 = random(1000000); + longValue2 = random(100000000); + boolValue1 = random(2) == 0; + boolValue2 = random(2) == 1; + floatValue = 12.34; + doubleValue = 1234.56789; + + //__FlashStringHelper cannot be declared outside a function + const __FlashStringHelper *flashCharArray2 = F("this is a string"); + + Log.notice("Log as Info with integer values : %d, %d" CR, intValue1, + intValue2); + Log.notice(F("Log as Info with hex values : %x, %X" CR), intValue1, + intValue1); + Log.notice("Log as Info with hex values : %x, %X" CR, intValue2, + intValue2); + Log.notice(F("Log as Info with binary values : %b, %B" CR), intValue1, + intValue1); + Log.notice("Log as Info with binary values : %b, %B" CR, intValue2, + intValue2); + Log.notice(F("Log as Info with long values : %l, %l" CR), longValue1, + longValue2); + Log.notice("Log as Info with bool values : %t, %T" CR, boolValue1, + boolValue2); + Log.notice(F("Log as Info with string value : %s" CR), charArray); + Log.notice("Log as Info with Flash string value : %S" CR, flashCharArray1); + Log.notice("Log as Info with Flash string value : %S" CR, flashCharArray2); + Log.notice("Log as Info with string value : %s" CR, stringValue1.c_str()); + Log.notice(F("Log as Info with float value : %F" CR), floatValue); + Log.notice("Log as Info with float value : %F" CR, floatValue); + Log.notice(F("Log as Info with double value : %D" CR), doubleValue); + Log.notice("Log as Info with double value : %D" CR, doubleValue); + Log.notice(F("Log as Debug with mixed values : %d, %d, %l, %l, %t, %T" CR), + intValue1, intValue2, longValue1, longValue2, boolValue1, + boolValue2); + + Log.trace("Log as Trace with bool value : %T" CR, boolValue1); + Log.traceln("Log as Trace with bool value : %T", boolValue1); + Log.warning("Log as Warning with bool value : %T" CR, boolValue1); + Log.warningln("Log as Warning with bool value : %T", boolValue1); + Log.error("Log as Error with bool value : %T" CR, boolValue1); + Log.errorln("Log as Error with bool value : %T", boolValue1); + Log.fatal("Log as Fatal with bool value : %T" CR, boolValue1); + Log.fatalln("Log as Fatal with bool value : %T", boolValue1); + Log.verboseln(F("Log as Verbose with bool value : %T"), boolValue2); + Log.verbose(F("Log as Verbose with bool value : %T" CR), boolValue2); + + Log.setPrefix(printTimestamp); // set timestamp as prefix + Log.setSuffix(printCarret); // set carret as suffix + Log.verboseln(F("Log with suffix & prefix")); + Log.setPrefix(NULL); // set timestamp as prefix + Log.setSuffix(NULL); // set carret as suffix + + delay(5000); +} +#endif \ No newline at end of file diff --git a/examples/platformio-basic/test/test_native.cpp b/examples/platformio-basic/test/test_native.cpp new file mode 100644 index 0000000..ce46efe --- /dev/null +++ b/examples/platformio-basic/test/test_native.cpp @@ -0,0 +1,325 @@ +#include "ArduinoLog.h" +#include +#include +#include +#include +#include +#include +#include + +using namespace fakeit; +std::stringstream output_; + +void reset_output() { + output_.str(std::string()); + output_.clear(); +} + +std::string decimal_to_binary(int n) { + + std::string binary; + while (n != 0) { + binary = (n % 2 == 0 ? "0" : "1") + binary; + n /= 2; + } + return binary; +} + +void TEST_ASSERT_EQUAL_STRING_STREAM(std::stringstream const &expected_output, + std::stringstream const &actual_output) { + + TEST_ASSERT_EQUAL_STRING(expected_output.str().c_str(), + actual_output.str().c_str()); +} + +void set_up_logging_captures() { + When(OverloadedMethod(ArduinoFake(Serial), println, size_t(void))) + .AlwaysDo([&]() -> int { + output_ << "\n"; + return 1; + }); + When(OverloadedMethod(ArduinoFake(Serial), print, size_t(char))) + .AlwaysDo([&](const char x) -> int { + output_ << x; + return 1; + }); + When(OverloadedMethod(ArduinoFake(Serial), print, size_t(const char[]))) + .AlwaysDo([&](const char x[]) -> int { + output_ << x; + return 1; + }); + When(OverloadedMethod(ArduinoFake(Serial), print, size_t(const String &))) + .AlwaysDo([&](const String &x) -> int { + output_ << x.c_str(); + return 1; + }); + When(OverloadedMethod(ArduinoFake(Serial), print, size_t(unsigned char, int))) + .AlwaysDo([&](unsigned char x, int y) -> int { + if (y == 2) { + output_ << decimal_to_binary(x); + } else { + output_ << std::setbase(y) << (unsigned long)x; + } + return 1; + }); + When(OverloadedMethod(ArduinoFake(Serial), print, size_t(unsigned long, int))) + .AlwaysDo([&](unsigned long x, int y) -> int { + output_ << std::fixed << std::setprecision(y) << x; + return 1; + }); + When(OverloadedMethod(ArduinoFake(Serial), print, size_t(int, int))) + .AlwaysDo([&](int x, int y) -> int { + if (y == 2) { + output_ << decimal_to_binary(x); + } else { + output_ << std::setbase(y) << x; + } + return 1; + }); + When(OverloadedMethod(ArduinoFake(Serial), print, size_t(unsigned int, int))) + .AlwaysDo([&](unsigned int x, int y) -> int { + if (y == 2) { + output_ << decimal_to_binary(x); + } else { + output_ << std::setbase(y) << x; + } + return 1; + }); + When(OverloadedMethod(ArduinoFake(Serial), print, size_t(double, int))) + .AlwaysDo([&](double x, int y) -> int { + output_ << std::fixed << std::setprecision(y) << x; + return 1; + }); + When(OverloadedMethod(ArduinoFake(Serial), print, size_t(long, int))) + .AlwaysDo([&](long x, int y) -> int { + if (y == 2) { + output_ << std::bitset(x).to_string(); + } else { + output_ << std::setbase(y) << x; + } + return 1; + }); + When(OverloadedMethod(ArduinoFake(Serial), print, size_t(unsigned long, int))) + .AlwaysDo([&](unsigned long x, int y) -> int { + if (y == 2) { + output_ << std::bitset(x).to_string(); + } else { + output_ << std::setbase(y) << x; + } + return 1; + }); + When(OverloadedMethod(ArduinoFake(Serial), print, + size_t(const __FlashStringHelper *ifsh))) + .AlwaysDo([&](const __FlashStringHelper *x) -> int { + auto message = reinterpret_cast(x); + output_ << message; + return 1; + }); + + When(Method(ArduinoFake(Serial), flush)).AlwaysReturn(); +} + +void setUp(void) { + ArduinoFakeReset(); + Log.begin(LOG_LEVEL_VERBOSE, &Serial); + set_up_logging_captures(); +} +void test_int_values() { + reset_output(); + int int_value1 = 173; + int int_value2 = 65536; + Log.notice("Log as Info with integer values : %d, %d" CR, int_value1, + int_value2); + std::stringstream expected_output; + expected_output << "N: Log as Info with integer values : 173, 65536\n"; + TEST_ASSERT_EQUAL_STRING_STREAM(expected_output, output_); +} + +void test_int_hex_values() { + reset_output(); + int int_value1 = 152; + int int_value2 = 65010; + Log.notice(F("Log as Info with hex values : %x, %X" CR), int_value1, + int_value1); + Log.notice("Log as Info with hex values : %x, %X" CR, int_value2, + int_value2); + std::stringstream expected_output; + expected_output << "N: Log as Info with hex values : 98, 0x0098\n" + << "N: Log as Info with hex values : fdf2, 0xfdf2\n"; + TEST_ASSERT_EQUAL_STRING_STREAM(expected_output, output_); +} + +void test_int_binary_values() { + reset_output(); + int int_value1 = 2218; + int int_value2 = 17814; + Log.notice(F("Log as Info with binary values : %b, %B" CR), int_value1, + int_value2); + std::stringstream expected_output; + expected_output << "N: Log as Info with binary values : 100010101010, " + "0b100010110010110\n"; + TEST_ASSERT_EQUAL_STRING_STREAM(expected_output, output_); +} +void test_long_values() { + reset_output(); + long long_value1 = 34359738368; + long long_value2 = 274877906944; + Log.notice(F("Log as Info with long values : %l, %l" CR), long_value1, + long_value2); + std::stringstream expected_output; + expected_output << "N: Log as Info with long values : " + "34359738368, 274877906944\n"; + TEST_ASSERT_EQUAL_STRING_STREAM(expected_output, output_); +} + +void test_bool_values() { + reset_output(); + bool true_value = true; + bool false_value = false; + Log.notice("Log as Info with bool values : %t, %T" CR, true_value, + true_value); + Log.notice("Log as Info with bool values : %t, %T" CR, false_value, + false_value); + std::stringstream expected_output; + expected_output << "N: Log as Info with bool values : T, true\n"; + expected_output << "N: Log as Info with bool values : F, false\n"; + TEST_ASSERT_EQUAL_STRING_STREAM(expected_output, output_); +} + +void test_char_string_values() { + reset_output(); + const char *charArray = "this is a string"; + Log.notice(F("Log as Info with string value : %s" CR), charArray); + std::stringstream expected_output; + expected_output << "N: Log as Info with string value : this is a string\n"; + TEST_ASSERT_EQUAL_STRING_STREAM(expected_output, output_); +} + +void test_flash_string_values() { + reset_output(); + //__FlashStringHelper cannot be declared outside a function + const __FlashStringHelper *flashCharArray2 = F("this is a string"); + + const char flashCharArray1[] PROGMEM = "this is a string"; + Log.notice("Log as Info with Flash string value : %S" CR, flashCharArray1); + std::stringstream expected_output; + expected_output + << "N: Log as Info with Flash string value : this is a string\n"; + TEST_ASSERT_EQUAL_STRING_STREAM(expected_output, output_); +} + +void test_string_values() { + reset_output(); + String stringValue1 = "this is a string"; + Log.notice("Log as Info with string value : %s" CR, stringValue1.c_str()); + std::stringstream expected_output; + expected_output << "N: Log as Info with string value : this is a string\n"; + TEST_ASSERT_EQUAL_STRING_STREAM(expected_output, output_); +} + +void test_float_values() { + reset_output(); + float float_value = 12.34; + Log.notice(F("Log as Info with float value : %F" CR), float_value); + Log.notice("Log as Info with float value : %F" CR, float_value); + std::stringstream expected_output; + expected_output << "N: Log as Info with float value : 12.34\n" + << "N: Log as Info with float value : 12.34\n"; + TEST_ASSERT_EQUAL_STRING_STREAM(expected_output, output_); +} + +void test_double_values() { + reset_output(); + double double_value = 1234.56789; + // Log.notice(F("%D" CR), double_value); + Log.notice(F("Log as Info with double value : %D" CR), double_value); + Log.notice("Log as Info with double value : %D" CR, double_value); + std::stringstream expected_output; + expected_output << "N: Log as Info with double value : 1234.57\n" + << "N: Log as Info with double value : 1234.57\n"; + TEST_ASSERT_EQUAL_STRING_STREAM(expected_output, output_); +} + +void test_mixed_values() { + reset_output(); + int int_value1 = 15826; + int int_value2 = 31477; + long long_value1 = 274877906944; + long long_value2 = 68719476743; + bool true_value = true; + bool false_value = false; + Log.notice(F("Log as Debug with mixed values : %d, %d, %l, %l, %t, %T" CR), + int_value1, int_value2, long_value1, long_value2, true_value, + false_value); + std::stringstream expected_output; + expected_output + << "N: Log as Debug with mixed values : 15826, 31477, 274877906944, " + "68719476743, T, false\n"; + TEST_ASSERT_EQUAL_STRING_STREAM(expected_output, output_); +} + +void test_log_levels() { + reset_output(); + bool true_value = true; + bool false_value = false; + Log.trace("Log as Trace with bool value : %T" CR, true_value); + Log.traceln("Log as Trace with bool value : %T", false_value); + Log.warning("Log as Warning with bool value : %T" CR, true_value); + Log.warningln("Log as Warning with bool value : %T", false_value); + Log.error("Log as Error with bool value : %T" CR, true_value); + Log.errorln("Log as Error with bool value : %T", false_value); + Log.fatal("Log as Fatal with bool value : %T" CR, true_value); + Log.fatalln("Log as Fatal with bool value : %T", false_value); + Log.verboseln(F("Log as Verbose with bool value : %T"), true_value); + Log.verbose(F("Log as Verbose with bool value : %T" CR), false_value); + std::stringstream expected_output; + expected_output << "T: Log as Trace with bool value : true\n" + "T: Log as Trace with bool value : false\n" + "W: Log as Warning with bool value : true\n" + "W: Log as Warning with bool value : false\n" + "E: Log as Error with bool value : true\n" + "E: Log as Error with bool value : false\n" + "F: Log as Fatal with bool value : true\n" + "F: Log as Fatal with bool value : false\n" + "V: Log as Verbose with bool value : true\n" + "V: Log as Verbose with bool value : false\n"; + TEST_ASSERT_EQUAL_STRING_STREAM(expected_output, output_); +} + +void printTimestamp(Print *_logOutput) { + char c[12]; + int m = sprintf(c, "%10lu ", millis()); + _logOutput->print(c); +} +void printCarret(Print *_logOutput) { _logOutput->print('>'); } + +void test_prefix_and_suffix() { + reset_output(); + When(Method(ArduinoFake(), millis)).Return(1026); + Log.setPrefix(printTimestamp); // set timestamp as prefix + Log.setSuffix(printCarret); // set carret as suffix + Log.verboseln(F("Log with suffix & prefix")); + Log.setPrefix(NULL); // clear prefix + Log.setSuffix(NULL); // clear suffix + std::stringstream expected_output; + expected_output << " 1026 V: Log with suffix & prefix>\n"; + TEST_ASSERT_EQUAL_STRING_STREAM(expected_output, output_); +} + +int main(int argc, char **argv) { + UNITY_BEGIN(); + RUN_TEST(test_int_values); + RUN_TEST(test_int_hex_values); + RUN_TEST(test_int_binary_values); + RUN_TEST(test_long_values); + RUN_TEST(test_bool_values); + RUN_TEST(test_char_string_values); + RUN_TEST(test_flash_string_values); + RUN_TEST(test_string_values); + RUN_TEST(test_float_values); + RUN_TEST(test_double_values); + RUN_TEST(test_mixed_values); + RUN_TEST(test_log_levels); + RUN_TEST(test_prefix_and_suffix); + UNITY_END(); +} \ No newline at end of file From 80c86ba04a379dd729cfad3155235c5aa24e34b6 Mon Sep 17 00:00:00 2001 From: Thijs Triemstra Date: Wed, 16 Jun 2021 16:31:58 +0200 Subject: [PATCH 28/32] fix typo --- examples/Log-advanced/Log-advanced.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/Log-advanced/Log-advanced.ino b/examples/Log-advanced/Log-advanced.ino index d40256d..2d0c867 100644 --- a/examples/Log-advanced/Log-advanced.ino +++ b/examples/Log-advanced/Log-advanced.ino @@ -58,18 +58,18 @@ void printTimestamp(Print* _logOutput) { const unsigned long SECS_PER_DAY = 86400; // Total time - const unsigned long msecs = millis() ; + const unsigned long msecs = millis(); const unsigned long secs = msecs / MSECS_PER_SEC; // Time in components - const unsigned long MiliSeconds = msecs % MSECS_PER_SEC; + const unsigned long MilliSeconds = msecs % MSECS_PER_SEC; const unsigned long Seconds = secs % SECS_PER_MIN ; const unsigned long Minutes = (secs / SECS_PER_MIN) % SECS_PER_MIN; const unsigned long Hours = (secs % SECS_PER_DAY) / SECS_PER_HOUR; // Time as string char timestamp[20]; - sprintf(timestamp, "%02d:%02d:%02d.%03d ", Hours, Minutes, Seconds, MiliSeconds); + sprintf(timestamp, "%02d:%02d:%02d.%03d ", Hours, Minutes, Seconds, MilliSeconds); _logOutput->print(timestamp); } From 7f8aa992c4c897e2ff9c6805463fedafb78c73be Mon Sep 17 00:00:00 2001 From: katutxakurra Date: Tue, 13 Jul 2021 10:40:41 +0100 Subject: [PATCH 29/32] Private _logOutput conditional compilation when DISABLE_LOGGING This avoids error: '_logOutput' was not declared in this scope when DISABLE_LOGGING is defined. --- ArduinoLog.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ArduinoLog.h b/ArduinoLog.h index 33e7564..9ec9fb0 100644 --- a/ArduinoLog.h +++ b/ArduinoLog.h @@ -328,7 +328,9 @@ class Logging void print(const Printable& obj, va_list args) { +#ifndef DISABLE_LOGGING _logOutput->print(obj); +#endif } void printFormat(const char format, va_list *args); @@ -382,4 +384,4 @@ class Logging #endif }; -extern Logging Log; \ No newline at end of file +extern Logging Log; From 1e68cd9ef93f6a15cb26288cfb972eac900c5191 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 16 Feb 2023 20:38:20 +0100 Subject: [PATCH 30/32] Fix: clearSuffix was clearing the prefix Fix: clearSuffix was clearing the prefix instead of the suffix --- ArduinoLog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ArduinoLog.cpp b/ArduinoLog.cpp index 538ea3d..c4075fe 100644 --- a/ArduinoLog.cpp +++ b/ArduinoLog.cpp @@ -96,7 +96,7 @@ void Logging::setSuffix(printfunction f) void Logging::clearSuffix() { #ifndef DISABLE_LOGGING - _prefix = nullptr; + _suffix = nullptr; #endif } From 39a46512a8c93b7c4560e4887095071215155bb6 Mon Sep 17 00:00:00 2001 From: Ivan Kravchenko Date: Mon, 22 Dec 2025 15:57:39 +0300 Subject: [PATCH 31/32] va_end missed --- ArduinoLog.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ArduinoLog.h b/ArduinoLog.h index 9ec9fb0..b51bb52 100644 --- a/ArduinoLog.h +++ b/ArduinoLog.h @@ -362,6 +362,7 @@ class Logging va_list args; va_start(args, msg); print(msg, args); + va_end(args); if(_suffix != NULL) { From 735a12d5ad93d3a2ff8ce1440287e368af4d9d45 Mon Sep 17 00:00:00 2001 From: Ivan Kravchenko Date: Mon, 22 Dec 2025 20:05:39 +0300 Subject: [PATCH 32/32] Register keyword was removed from C++17 standart. --- ArduinoLog.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ArduinoLog.cpp b/ArduinoLog.cpp index c4075fe..f8ae7e8 100644 --- a/ArduinoLog.cpp +++ b/ArduinoLog.cpp @@ -172,12 +172,12 @@ void Logging::printFormat(const char format, va_list *args) { } else if (format == 's') { - register char *s = va_arg(*args, char *); + char *s = va_arg(*args, char *); _logOutput->print(s); } else if (format == 'S') { - register __FlashStringHelper *s = va_arg(*args, __FlashStringHelper *); + __FlashStringHelper *s = va_arg(*args, __FlashStringHelper *); _logOutput->print(s); } else if (format == 'd' || format == 'i') @@ -196,7 +196,7 @@ void Logging::printFormat(const char format, va_list *args) { { _logOutput->print("0x"); //_logOutput->print(va_arg(*args, int), HEX); - register uint16_t h = (uint16_t) va_arg( *args, int ); + uint16_t h = (uint16_t) va_arg( *args, int ); if (h<0xFFF) _logOutput->print('0'); if (h<0xFF ) _logOutput->print('0'); if (h<0xF ) _logOutput->print('0'); @@ -204,7 +204,7 @@ void Logging::printFormat(const char format, va_list *args) { } else if (format == 'p') { - register Printable *obj = (Printable *) va_arg(*args, int); + Printable *obj = (Printable *) va_arg(*args, int); _logOutput->print(*obj); } else if (format == 'b') @@ -229,7 +229,7 @@ void Logging::printFormat(const char format, va_list *args) { _logOutput->print((char) va_arg(*args, int)); } else if( format == 'C' ) { - register char c = (char) va_arg( *args, int ); + char c = (char) va_arg( *args, int ); if (c>=0x20 && c<0x7F) { _logOutput->print(c); } else {