etherlab/plc_etherlab.c
author Andrey Skvortsov <andrej.skvortzov@gmail.com>
Tue, 26 Jun 2018 17:34:15 +0300
changeset 2229 3c94bac4526e
parent 2165 02a2b5dee5e3
child 2641 c9deff128c37
permissions -rw-r--r--
Fix 'DoGetTextExtent - invalid DC' error

most likely this error happens only on certain wx backends.
GTK3+ on GNU/Linux is apparently one of them.
The problem is described in wxWidgets issue tracker.
http://trac.wxwidgets.org/ticket/12486

[-------------------------------------------------------------------------------------------------------------------]
platform:
Linux-4.16.0-2-rt-amd64-x86_64-with-debian-buster-sid

python-version:
2.7.15

traceback:
File "/home/developer/WorkData/PLC/beremiz/beremiz/ProjectController.py", line 1605, in DispatchDebugValuesProc
self.CallWeakcallables("__tick__", "NewDataAvailable", debug_ticks)
File "/home/developer/WorkData/PLC/beremiz/beremiz/ProjectController.py", line 1585, in CallWeakcallables
function(*cargs)
File "/home/developer/WorkData/PLC/beremiz/beremiz/editors/Viewer.py", line 1217, in NewDataAvailable
refresh_rect.Union(element.GetRedrawRect())
File "/home/developer/WorkData/PLC/beremiz/beremiz/graphics/GraphicCommons.py", line 1609, in GetRedrawRect
self.ValueSize = self.Parent.GetMiniTextExtent(self.ComputedValue)
File "/home/developer/WorkData/PLC/beremiz/beremiz/editors/Viewer.py", line 932, in GetMiniTextExtent
return self.MiniTextDC.GetTextExtent(text)
File "/usr/lib/python2.7/dist-packages/wx-3.0-gtk3/wx/_gdi.py", line 4127, in GetTextExtent
return _gdi_.DC_GetTextExtent(*args, **kwargs)
<class 'wx._core.PyAssertionError'>: C++ assertion "m_graphicContext" failed at ../src/common/dcgraph.cpp(1160) in DoGetTextExtent(): wxGCDC(cg)::DoGetTextExtent - invalid DC

wx-platform:
__WXGTK__

wx-version:
3.0.2.0

[-------------------------------------------------------------------------------------------------------------------]

traceback:
File "/home/developer/WorkData/PLC/beremiz/beremiz/controls/LogViewer.py", line 740, in OnMessageToolTipTimer
self.MessageToolTip.SetFont(self.Font)
File "/home/developer/WorkData/PLC/beremiz/beremiz/controls/CustomToolTip.py", line 75, in SetFont
self.RefreshTip()
File "/home/developer/WorkData/PLC/beremiz/beremiz/controls/CustomToolTip.py", line 158, in RefreshTip
self.SetClientSize(self.GetToolTipSize())
File "/home/developer/WorkData/PLC/beremiz/beremiz/controls/CustomToolTip.py", line 145, in GetToolTipSize
w, h = dc.GetTextExtent(line)
File "/usr/lib/python2.7/dist-packages/wx-3.0-gtk3/wx/_gdi.py", line 4127, in GetTextExtent
return _gdi_.DC_GetTextExtent(*args, **kwargs)
<class 'wx._core.PyAssertionError'>: C++ assertion "m_graphicContext" failed at ../src/common/dcgraph.cpp(1160) in DoGetTextExtent(): wxGCDC(cg)::DoGetTextExtent - invalid DC

[-------------------------------------------------------------------------------------------------------------------]
/*

Template C code used to produce target Ethercat C code

Copyright (C) 2011-2014: Laurent BESSARD, Edouard TISSERANT

Distributed under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

See COPYING file for copyrights details.

*/

#include <rtdm/rtdm.h>
#include <native/task.h>
#include <native/timer.h>

#include "ecrt.h"

#include "beremiz.h"
#include "iec_types_all.h"

// declaration of interface variables
%(located_variables_declaration)s

// process data
uint8_t *domain1_pd = NULL;
%(used_pdo_entry_offset_variables_declaration)s

const static ec_pdo_entry_reg_t domain1_regs[] = {
%(used_pdo_entry_configuration)s
    {}
};
/*****************************************************************************/

%(pdos_configuration_declaration)s

long long wait_period_ns = 100000LL;

// EtherCAT
static ec_master_t *master = NULL;
static ec_domain_t *domain1 = NULL;
static int first_sent=0;
%(slaves_declaration)s
#define SLOGF(level, format, args...)\
{\
    char sbuf[256];\
    int slen = snprintf(sbuf , sizeof(sbuf) , format , ##args);\
    LogMessage(level, sbuf, slen);\
}

/* Beremiz plugin functions */
int __init_%(location)s(int argc,char **argv)
{
    uint32_t abort_code;
    size_t result_size;
    
    abort_code = 0;
    result_size = 0;

    master = ecrt_request_master(%(master_number)d);
    if (!master) {
        SLOGF(LOG_CRITICAL, "EtherCAT master request failed!");
        return -1;
    }

    if(!(domain1 = ecrt_master_create_domain(master))){
        SLOGF(LOG_CRITICAL, "EtherCAT Domain Creation failed!");
        goto ecat_failed;
    }

    // slaves PDO configuration
%(slaves_configuration)s

    if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) {
        SLOGF(LOG_CRITICAL, "EtherCAT PDO registration failed!");
        goto ecat_failed;
    }

    ecrt_master_set_send_interval(master, common_ticktime__);

    // slaves initialization
%(slaves_initialization)s

    // extracting default value for not mapped entry in output PDOs
%(slaves_output_pdos_default_values_extraction)s

    if (ecrt_master_activate(master)){
        SLOGF(LOG_CRITICAL, "EtherCAT Master activation failed");
        goto ecat_failed;
    }

    if (!(domain1_pd = ecrt_domain_data(domain1))) {
        SLOGF(LOG_CRITICAL, "Failed to map EtherCAT process data");
        goto ecat_failed;
    }

    SLOGF(LOG_INFO, "Master %(master_number)d activated.");
    
    first_sent = 0;

    return 0;

ecat_failed:
    ecrt_release_master(master);
    return -1;

}

void __cleanup_%(location)s(void)
{
    //release master
    ecrt_release_master(master);
    first_sent = 0;
}

void __retrieve_%(location)s(void)
{
    // receive ethercat
    if(first_sent){
        ecrt_master_receive(master);
        ecrt_domain_process(domain1);
%(retrieve_variables)s
    }

}

static RTIME _last_occur=0;
static RTIME _last_publish=0;
RTIME _current_lag=0;
RTIME _max_jitter=0;
static inline RTIME max(RTIME a,RTIME b){return a>b?a:b;}

void __publish_%(location)s(void)
{
%(publish_variables)s
    ecrt_domain_queue(domain1);
    {
        RTIME current_time = rt_timer_read();
        // Limit spining max 1/5 of common_ticktime
        RTIME maxdeadline = current_time + (common_ticktime__ / 5);
        RTIME deadline = _last_occur ? 
            _last_occur + common_ticktime__ : 
            current_time + _max_jitter; 
        if(deadline > maxdeadline) deadline = maxdeadline;
        _current_lag = deadline - current_time;
        if(_last_publish != 0){
            RTIME period = current_time - _last_publish;
            if(period > common_ticktime__ )
                _max_jitter = max(_max_jitter, period - common_ticktime__);
            else
                _max_jitter = max(_max_jitter, common_ticktime__ - period);
        }
        _last_publish = current_time;
        _last_occur = current_time;
        while(current_time < deadline) {
            _last_occur = current_time; //Drift backward by default
            current_time = rt_timer_read();
        }
        if( _max_jitter * 10 < common_ticktime__ && _current_lag < _max_jitter){
            //Consuming security margin ?
            _last_occur = current_time; //Drift forward
        }
    }
    ecrt_master_send(master);
    first_sent = 1;
}