diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b168b8c --- /dev/null +++ b/.gitignore @@ -0,0 +1,367 @@ +#### 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 + +# Cmake +cmake*/ +CMakeListsPrivate.txt + +# PlatformIO IDE data +.pio/ + +# Jetbrains IDE configuration +.idea/ \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 167bd7b..992647a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,16 +15,18 @@ "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", "os": "linux" -} +} \ No newline at end of file diff --git a/ArduinoLog.cpp b/ArduinoLog.cpp index 4dba1aa..f8ae7e8 100644 --- a/ArduinoLog.cpp +++ b/ArduinoLog.cpp @@ -5,7 +5,7 @@ /_/ \_\_|_\___/ \___/|___|_|\_|\___/|____\___/ \___| Log library for Arduino - version 1.0.3 + version 1.1.1 https://github.com/thijse/Arduino-Log Licensed under the MIT License . @@ -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,57 +93,91 @@ void Logging::setSuffix(printfunction f) #endif } +void Logging::clearSuffix() +{ +#ifndef DISABLE_LOGGING + _suffix = nullptr; +#endif +} + 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 } void Logging::printFormat(const char format, va_list *args) { #ifndef DISABLE_LOGGING + if (format == '\0') return; if (format == '%') { _logOutput->print(format); } else if (format == 's') { - register char *s = (char *)va_arg(*args, int); + char *s = va_arg(*args, char *); _logOutput->print(s); } else if (format == 'S') { - register __FlashStringHelper *s = (__FlashStringHelper *)va_arg(*args, int); + __FlashStringHelper *s = va_arg(*args, __FlashStringHelper *); _logOutput->print(s); } else if (format == 'd' || format == 'i') @@ -152,9 +193,19 @@ void Logging::printFormat(const char format, va_list *args) { _logOutput->print(va_arg(*args, int), HEX); } else if (format == 'X') - { + { _logOutput->print("0x"); - _logOutput->print(va_arg(*args, int), HEX); + //_logOutput->print(va_arg(*args, int), HEX); + 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 == 'p') + { + Printable *obj = (Printable *) va_arg(*args, int); + _logOutput->print(*obj); } else if (format == 'b') { @@ -169,10 +220,24 @@ 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)); } + else if( format == 'C' ) { + 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) diff --git a/ArduinoLog.h b/ArduinoLog.h index 6cab7f0..b51bb52 100644 --- a/ArduinoLog.h +++ b/ArduinoLog.h @@ -5,26 +5,33 @@ /_/ \_\_|_\___/ \___/|___|_|\_|\___/|____\___/ \___| Log library for Arduino - version 1.0.3 + version 1.1.1 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 - #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*); +typedef void (*printfunction)(Print*, int); + -//#include -//#include // ************************************************************************* // Uncomment line below to fully disable logging, and reduce project size // ************************************************************************ @@ -34,37 +41,40 @@ 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 #define CR "\n" -#define LOGGING_VERSION 1_0_3 +#define LF "\r" +#define NL "\n\r" +#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 * @@ -72,7 +82,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 */ @@ -86,8 +97,8 @@ class Logging Logging() #ifndef DISABLE_LOGGING : _level(LOG_LEVEL_SILENT), - _showLevel(true), - _logOutput(NULL) + _showLevel(true), + _logOutput(NULL) #endif { @@ -145,6 +156,13 @@ class Logging */ void setPrefix(printfunction f); + /** + * clears prefix. + * + * \return void + */ + void clearPrefix(); + /** * Sets a function to be called after each log command. * @@ -153,6 +171,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 @@ -163,12 +188,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 +210,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 +231,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 +253,29 @@ 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 + } + + 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 @@ -230,10 +287,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,35 +309,52 @@ 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); void print(const __FlashStringHelper *format, va_list args); + void print(const Printable& obj, va_list args) + { +#ifndef DISABLE_LOGGING + _logOutput->print(obj); +#endif + } + 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) { return; } + if (level < LOG_LEVEL_SILENT) + { + level = LOG_LEVEL_SILENT; + } + 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(": "); } @@ -283,10 +362,15 @@ class Logging va_list args; va_start(args, msg); print(msg, args); + va_end(args); if(_suffix != NULL) { - _suffix(_logOutput); + _suffix(_logOutput, level); + } + if (cr) + { + _logOutput->print(CR); } #endif } @@ -302,5 +386,3 @@ class Logging }; extern Logging Log; -#endif - diff --git a/Images/logo.png b/Images/logo.png new file mode 100644 index 0000000..88f4475 Binary files /dev/null and b/Images/logo.png differ diff --git a/LICENSE.md b/LICENSE.md index b4d0fa4..554b7df 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,7 +1,7 @@ MIT License -Copyright (c) 2017,2018 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 cd0bb23..628cd76 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ +![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) [![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. @@ -20,6 +21,7 @@ ArduinoLog is a minimalistic framework to help the programmer output log stateme * All Arduino boards (Uno, Due, Mini, Micro, Yun...) * ESP8266 +* ESP32 ## Downloading @@ -48,7 +50,8 @@ 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 @@ -77,7 +80,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. @@ -101,27 +104,66 @@ 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` -* %b display as binary number -* %B display as binary number, prefixed by `0b' +* %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 ``` - 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. Some terminals prefer `NL` (New line). + +### 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 + +Advanced features are demonstrated in [Log-advanced](examples/Log-advanced/Log-advanced.ino) example. -### Storing messages in Flash memory +### 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); +``` + +[this example](https://forum.arduino.cc/t/printable-classes/438816) shows how to make your own classes printable + + ### 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); +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. @@ -130,28 +172,23 @@ 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); } ``` -### Examples +### Custom logging format +You can modify your logging format by defining a custom prefix & suffix for each log line. For example: ```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 ); +void printPrefix(Print* _logOutput, int logLevel) { + printTimestamp(_logOutput); + printLogLevel (_logOutput, logLevel); +} ``` - -### Disable library - -(if your code is completely tested) all logging code can be compiled out. Do this by uncommenting -```c++ -#define DISABLE_LOGGING +will result in log timestamps very similar to e.g. NLOG: +``` +00:47:51.432 VERBOSE Message to be logged ``` -in `Logging.h`. This may significantly reduce your project size. ## Credit @@ -165,7 +202,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/ChristianBauerAMDC) ## On using and modifying libraries @@ -174,4 +216,4 @@ Bugfixes & features by ## Copyright -ArduinoLog is provided Copyright © 2017,2018, 2019 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..2d0c867 --- /dev/null +++ b/examples/Log-advanced/Log-advanced.ino @@ -0,0 +1,94 @@ +#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 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, MilliSeconds); + _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(""); +} diff --git a/examples/Log/Log.ino b/examples/Log-basic/Log-basic.ino similarity index 67% rename from examples/Log/Log.ino rename to examples/Log-basic/Log-basic.ino index e783d2b..181292b 100644 --- a/examples/Log/Log.ino +++ b/examples/Log-basic/Log-basic.ino @@ -1,14 +1,21 @@ #include +/* + _ ___ ___ _ _ ___ _ _ ___ _ ___ ___ + /_\ | _ \ \| | | |_ _| \| |/ _ \| | / _ \ / __| + / _ \| / |) | |_| || || .` | (_) | |_| (_) | (_ | + /_/ \_\_|_\___/ \___/|___|_|\_|\___/|____\___/ \___| -/*! -* This example sketch shows most of the features of the ArduinoLog library -* -*/ + 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"; @@ -22,19 +29,18 @@ void setup() { 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 + // 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); - //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 + Log.notice(F("******************* ")); Log.notice("*********************** " CR); // two info strings without newline will end up on same line } void loop() { @@ -48,8 +54,6 @@ void loop() { floatValue = 12.34; doubleValue= 1234.56789; - //__FlashStringHelper cannot be declared oustide 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); @@ -58,31 +62,29 @@ 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); 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.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.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'); -} + 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/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 diff --git a/keywords.txt b/keywords.txt index f338673..9204507 100644 --- a/keywords.txt +++ b/keywords.txt @@ -15,19 +15,34 @@ Log KEYWORD1 # Methods and Functions (KEYWORD2) ####################################### fatal KEYWORD2 +fatalln KEYWORD2 error KEYWORD2 +errorln KEYWORD2 warning KEYWORD2 +warningln KEYWORD2 +info KEYWORD2 +infoln 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 +clearPrefix KEYWORD2 +clearSuffix KEYWORD2 ####################################### # Instances (KEYWORD2) ####################################### Logging KEYWORD2 +Log KEYWORD2 ####################################### # Constants (LITERAL1) @@ -37,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 7b61150..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.3", + "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 a203815..1279f4a 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ name=ArduinoLog -version=1.0.3 +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=*