targets/plc_debug.c
author greg
Wed, 10 Dec 2008 17:37:21 +0100
changeset 274 8628f3dd0979
parent 244 85e92d9e34a8
child 280 f2ef79f3dba0
permissions -rw-r--r--
Adding support for defining plugin library as a plcopen xml file in plugin folder
/*
 * DEBUGGER code
 * 
 * On "publish", when buffer is free, debugger stores arbitrary variables 
 * content into, and mark this buffer as filled
 * 
 * 
 * Buffer content is read asynchronously, (from non real time part), 
 * and then buffer marked free again.
 *  
 * 
 * */
#include "iec_types_all.h"
#include "POUS.h"
/*for memcpy*/
#include <string.h>

#define BUFFER_SIZE 1024
#define MAX_SUBSCRIBTION %(subscription_table_count)d

/* Atomically accessed variable for buffer state */
#define BUFFER_FREE 0
#define BUFFER_BUSY 1
static long buffer_state = BUFFER_FREE;

/* The buffer itself */
char debug_buffer[BUFFER_SIZE];

/* Buffer's cursor*/
static char* buffer_cursor = debug_buffer;

typedef struct{
    void* ptrvalue;
    __IEC_types_enum type;
}struct_plcvar;

/***
 * Declare programs 
 **/
%(programs_declarations)s

/***
 * Declare global variables from resources and conf 
 **/
%(extern_variables_declarations)s

static int subscription_table[MAX_SUBSCRIBTION];
static int* latest_subscription = subscription_table;
static int* subscription_cursor = subscription_table;

struct_plcvar variable_table[%(variables_pointer_type_table_count)d];

void __init_debug()
{
%(variables_pointer_type_table_initializer)s
AtomicCompareExchange(
            &buffer_state,
            BUFFER_BUSY,
            BUFFER_FREE);
}

void __cleanup_debug()
{
}

void __retrieve_debug()
{
}

extern int TryEnterDebugSection(void);
extern void LeaveDebugSection(void);

extern int __tick;
void __publish_debug()
{
    /* Check there is no running debugger re-configuration */
    if(TryEnterDebugSection()){
        /* Lock buffer */
        long latest_state = AtomicCompareExchange(
            &buffer_state,
            BUFFER_FREE,
            BUFFER_BUSY);
            
        /* If buffer was free */
        if(latest_state == BUFFER_FREE)
        {
            int* subscription;
            
            /* Reset buffer cursor */
            buffer_cursor = debug_buffer;
            
            /* iterate over subscriptions */
            for(subscription=subscription_table;
                subscription < latest_subscription;
                subscription++)
            {
                /* get variable descriptor */
                struct_plcvar* my_var = &variable_table[*subscription];
                char* next_cursor;
                /* get variable size*/
                USINT size = __get_type_enum_size(my_var->type);
                /* compute next cursor positon*/
                next_cursor = buffer_cursor + size;
                /* if buffer not full */
                if(next_cursor < debug_buffer + BUFFER_SIZE)
                {
                    /* copy data to the buffer */
                    memcpy(buffer_cursor, my_var->ptrvalue, size);
                    /* increment cursor according size*/
                    buffer_cursor = next_cursor;
                }else{
                    /*TODO : signal overflow*/
                }
            }
    
            /* Reset buffer cursor again (for IterDebugData)*/
            buffer_cursor = debug_buffer;
            subscription_cursor = subscription_table;
            
            /* Leave debug section,
             * Trigger asynchronous transmission 
             * (returns immediately) */
            InitiateDebugTransfer(); /* size */
        }
        LeaveDebugSection();
    }
}

void RegisterDebugVariable(int idx)
{
    /*If subscription table not full */
    if(latest_subscription - subscription_table < MAX_SUBSCRIBTION)
    {
        *(latest_subscription++) = idx;
        /* TODO pre-calc buffer size and signal overflow*/
    }else{
        /*TODO : signal subscription overflow*/
    }
}

void ResetDebugVariables(void)
{
    latest_subscription = subscription_table;
}

void FreeDebugData()
{
    /* atomically mark buffer as free */
    long latest_state = AtomicCompareExchange(
        &buffer_state,
        BUFFER_BUSY,
        BUFFER_FREE);
}

void* IterDebugData(int* idx, const char **type_name)
{
    if(subscription_cursor < latest_subscription){
        char* old_cursor = buffer_cursor;
        *idx = *subscription_cursor;
        struct_plcvar* my_var = &variable_table[*(subscription_cursor++)];
        *type_name = __get_type_enum_name(my_var->type);
        /* get variable size*/
        USINT size = __get_type_enum_size(my_var->type);
        /* compute next cursor positon*/
        buffer_cursor = buffer_cursor + size;
        if(old_cursor < debug_buffer + BUFFER_SIZE)
        {
            return old_cursor;
        }else{
            return NULL;
        } 
    }
    *idx = -1;
    *type_name = NULL;
    return NULL;
}