# lint Python modules using external checkers. # # This is the main checker controling the other ones and the reports # generation. It is itself both a raw checker and an astng checker in order # to: # * handle message activation / deactivation at the module level # * handle some basic but necessary stats'data (number of classes, methods...) # # This checker also defines the following reports: # * R0001: Total errors / warnings # * R0002: % errors / warnings by module # * R0003: Messages # * R0004: Global evaluation # [MASTER] # Add to the black list. It should be a base name, not a # path. You may set this option multiple times. ignore=CVS # Pickle collected data for later comparisons. persistent=yes # Set the cache size for astng objects. cache-size=500 [REPORTS] # Tells wether to display a full report or only the messages reports=yes # Use HTML as output format instead of text html=no # Use a parseable text output format, so your favorite text editor will be able # to jump to the line corresponding to a message. parseable=no # Colorizes text output using ansi escape codes color=no # Put messages in a separate file for each module / package specified on the # command line instead of printing them on stdout. Reports (if any) will be # written in a file name "pylint_global.[txt|html]". files-output=no # Python expression which should return a note less than 10 (10 is the highest # note).You have access to the variables errors warning, statement which # respectivly contain the number of errors / warnings messages and the total # number of statements analyzed. This is used by the global evaluation report # (R0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) # Add a comment according to your evaluation note. This is used by the global # evaluation report (R0004). comment=no # Include message's id in output include-ids=yes # checks for # * unused variables / imports # * undefined variables # * redefinition of variable from builtins or from an outer scope # * use of variable before assigment # [VARIABLES] # Enable / disable this checker enable-variables=yes # Tells wether we should check for unused import in __init__ files. init-import=no # List of variable names used for dummy variables (i.e. not used). dummy-variables=_,_1,_2,_3,_4,_5,dummy # checks for : # * doc strings # * modules / classes / functions / methods / arguments / variables name # * number of arguments, local variables, branchs, returns and statements in # functions, methods # * required module attributes # * dangerous default values as arguments # * redefinition of function / method / class # * uses of the global statement # # This checker also defines the following reports: # * R0101: Statistics by type # [BASIC] # Enable / disable this checker enable-basic=yes # Required attributes for module, separated by a comma required-attributes= # Regular expression which should only match functions or classes name which do # not require a docstring no-docstring-rgx=.* # Minimal length for module / class / function / method / argument / variable # names min-name-length=1 # Regular expression which should only match correct module names module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ # Regular expression which should only match correct class names class-rgx=[A-Z_][a-zA-Z0-9]+$ # Regular expression which should only match correct function names function-rgx=[a-z_][A-Za-z0-9_]*$ # Regular expression which should only match correct method names method-rgx=[a-z_][A-Za-z0-9_]*$ # Regular expression which should only match correct argument names argument-rgx=[a-z_][A-Za-z0-9_]*$ # Regular expression which should only match correct variable names variable-rgx=[a-z_][A-Za-z0-9_]*$ # Good variable names which should always be accepted, separated by a comma good-names=i,j,k,ex,Run,_ # Bad variable names which should always be refused, separated by a comma bad-names=foo,bar,baz,toto,tutu,tata # List of builtins function names that should not be used, separated by a comma bad-functions=apply,input # checks for sign of poor/misdesign: # * number of methods, attributes, local variables... # * size, complexity of functions, methods # [DESIGN] # Enable / disable this checker enable-design=yes # Maximum number of arguments for function / method max-args=15 # Maximum number of locals for function / method body max-locals=15 # Maximum number of return / yield for function / method body max-returns=6 # Maximum number of branch for function / method body max-branchs=12 # Maximum number of statements in function / method body max-statements=50 # Maximum number of parents for a class (see R0901). max-parents=7 # Maximum number of attributes for a class (see R0902). max-attributes=7 # Minimum number of public methods for a class (see R0903). min-public-methods=2 # Maximum number of public methods for a class (see R0904). max-public-methods=20 # checks for : # * methods without self as first argument
#include "variable_trace.h"
#include <stddef.h>
#include <string.h>

#ifdef NO_PRINT
#error "You need undef NO_PRINT to use the variable trace feature"
#endif

#ifndef CONSOLE_ENABLE
#error "The console needs to be enabled in the makefile to use the variable trace feature"
#endif


#define NUM_TRACED_VARIABLES 1
#ifndef MAX_VARIABLE_TRACE_SIZE
    #define MAX_VARIABLE_TRACE_SIZE 4
#endif

typedef struct {
    const char* name;
    void* addr;
    unsigned size;
    const char* func;
    int line;
    uint8_t last_value[MAX_VARIABLE_TRACE_SIZE];

} traced_variable_t;

static traced_variable_t traced_variables[NUM_TRACED_VARIABLES];

void add_traced_variable(const char* name, void* addr, unsigned size, const char* func, int line) {
    verify_traced_variables(func, line);
    if (size > MAX_VARIABLE_TRACE_SIZE) {
#if defined(__AVR__)
       xprintf("Traced variable \"%S\" exceeds the maximum size %d\n", name, size);
#else
       xprintf("Traced variable \"%s\" exceeds the maximum size %d\n", name, size);
#endif
       size = MAX_VARIABLE_TRACE_SIZE;
    }
    int index = -1;
    for (int i = 0; i < NUM_TRACED_VARIABLES; i++) {
        if (index == -1 && traced_variables[i].addr == NULL){
            index = i;
        }
        else if (strcmp_P(name, traced_variables[i].name)==0) {
            index = i;
            break;
        }
    }

    if (index == -1) {
        xprintf("You can only trace %d variables at the same time\n", NUM_TRACED_VARIABLES);
        return;
    }

    traced_variable_t* t = &traced_variables[index];
    t->name = name;
    t->addr = addr;
    t->size = size;
    t->func = func;
    t->line = line;
    memcpy(&t->last_value[0], addr, size);

}

void remove_traced_variable(const char* name, const char* func, int line) {
    verify_traced_variables(func, line);
    for (int i = 0; i < NUM_TRACED_VARIABLES; i++) {
        if (strcmp_P(name, traced_variables[i].name)==0) {
            traced_variables[i].name = 0;
            traced_variables[i].addr = NULL;
            break;
        }
    }
}

void verify_traced_variables(const char* func, int line) {
    for (int i = 0; i < NUM_TRACED_VARIABLES; i++) {
        traced_variable_t* t = &traced_variables[i];
        if (t->addr != NULL && t->name != NULL) {
            if (memcmp(t->last_value, t->addr, t->size)!=0){
#if defined(__AVR__)
               xprintf("Traced variable \"%S\" has been modified\n", t->name);
               xprintf("Between %S:%d\n", t->func, t->line);
               xprintf("And %S:%d\n", func, line);

#else
               xprintf("Traced variable \"%s\" has been modified\n", t->name);
               xprintf("Between %s:%d\n", t->func, t->line);
               xprintf("And %s:%d\n", func, line);
#endif
               xprintf("Previous value ");
               for (int j=0; j<t->size;j++) {
                   print_hex8(t->last_value[j]);
               }
               xprintf("\nNew value ");
               uint8_t* addr = (uint8_t*)(t->addr);
               for (int j=0; j<t->size;j++) {
                   print_hex8(addr[j]);
               }
               xprintf("\n");
               memcpy(t->last_value, addr, t->size);
           }
        }

        t->func = func;
        t->line = line;
    }
}