* Xenomai Linux specific code
#include <alchemy/task.h>
#include <alchemy/timer.h>
#include <alchemy/pipe.h>
unsigned int PLC_state = 0;
#define PLC_STATE_TASK_CREATED 1
#define PLC_STATE_DEBUG_PIPE_CREATED 2
#define PLC_STATE_PYTHON_PIPE_CREATED 8
#define PLC_STATE_WAITDEBUG_PIPE_CREATED 16
#define PLC_STATE_WAITPYTHON_PIPE_CREATED 32
#define PYTHON_PENDING_COMMAND 1
#define DEBUG_PENDING_DATA 1
long AtomicCompareExchange(long* atomicvar,long compared, long exchange)
return __sync_val_compare_and_swap(atomicvar, compared, exchange);
long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange)
return __sync_val_compare_and_swap(atomicvar, compared, exchange);
void PLC_GetTime(IEC_TIME *CURRENT_TIME)
RTIME current_time = rt_timer_read();
CURRENT_TIME->tv_sec = current_time / 1000000000;
CURRENT_TIME->tv_nsec = current_time % 1000000000;
struct RT_to_nRT_signal_s {
typedef struct RT_to_nRT_signal_s RT_to_nRT_signal_t;
#define max_RT_to_nRT_signals 16
static RT_to_nRT_signal_t RT_to_nRT_signal_pool[max_RT_to_nRT_signals];
int recv_RT_to_nRT_signal(void* handle, char* payload){
RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t*)handle;
if(!sig->used) return -EINVAL;
return read(sig->pipe_fd, payload, 1);
int send_RT_to_nRT_signal(void* handle, char payload){
RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t*)handle;
if(!sig->used) return -EINVAL;
return rt_pipe_write(&sig->pipe, &payload, 1, P_NORMAL);
void PLC_SetTimer(unsigned long long next, unsigned long long period)
RTIME current_time = rt_timer_read();
rt_task_set_periodic(&PLC_task, current_time + next, rt_timer_ns2ticks(period));
void PLC_task_proc(void *arg)
PLC_SetTimer(common_ticktime__, common_ticktime__);
PLC_GetTime(&__CURRENT_TIME);
rt_task_wait_period(NULL);
/* since xenomai 3 it is not enough to close()
file descriptor to unblock read()... */
/* explicitely finish python thread */
char msg = PYTHON_FINISH;
send_RT_to_nRT_signal(WaitPython_handle, msg);
/* explicitely finish debug thread */
send_RT_to_nRT_signal(WaitDebug_handle, msg);
static unsigned long __debug_tick;
#define _Log(text, err) \
snprintf(mstr, 255, text " for %s (%d)", name, err);\
LogMessage(LOG_CRITICAL, mstr, strlen(mstr));\
void *create_RT_to_nRT_signal(char* name){
for(int i=0; i < max_RT_to_nRT_signals; i++){
sig = &RT_to_nRT_signal_pool[i];
_Log("Maximum count of RT-PIPE reached while creating pipe", max_RT_to_nRT_signals);
if(ret = rt_pipe_create(&sig->pipe, name, new_index, PIPE_SIZE) < 0){
_Log("Failed opening real-time end of RT-PIPE", ret);
/* open pipe's userland */
snprintf(pipe_dev, 63, "/dev/rtp%d", new_index);
if((sig->pipe_fd = open(pipe_dev, O_RDWR)) == -1){
rt_pipe_delete(&sig->pipe);
_Log("Failed opening non-real-time end of RT-PIPE", errno);
void delete_RT_to_nRT_signal(void* handle){
RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t*)handle;
if(ret = rt_pipe_delete(&sig->pipe) != 0){
_Log("Failed closing real-time end of RT-PIPE", ret);
if(close(sig->pipe_fd) != 0){
_Log("Failed closing non-real-time end of RT-PIPE", errno);
int wait_RT_to_nRT_signal(void* handle){
int ret = recv_RT_to_nRT_signal(handle, &cmd);
return (ret == 1) ? 0 : ((ret == 0) ? ENODATA : -ret);
int unblock_RT_to_nRT_signal(void* handle){
int ret = send_RT_to_nRT_signal(handle, 0);
return (ret == 1) ? 0 : ((ret == 0) ? EINVAL : -ret);
void nRT_reschedule(void){
void PLC_cleanup_all(void)
if (PLC_state & PLC_STATE_TASK_CREATED) {
rt_task_delete(&PLC_task);
PLC_state &= ~PLC_STATE_TASK_CREATED;
if (PLC_state & PLC_STATE_WAITDEBUG_PIPE_CREATED) {
delete_RT_to_nRT_signal(WaitDebug_handle);
PLC_state &= ~PLC_STATE_WAITDEBUG_PIPE_CREATED;
if (PLC_state & PLC_STATE_WAITPYTHON_PIPE_CREATED) {
delete_RT_to_nRT_signal(WaitPython_handle);
PLC_state &= ~PLC_STATE_WAITPYTHON_PIPE_CREATED;
if (PLC_state & PLC_STATE_DEBUG_PIPE_CREATED) {
delete_RT_to_nRT_signal(Debug_handle);
PLC_state &= ~PLC_STATE_DEBUG_PIPE_CREATED;
if (PLC_state & PLC_STATE_PYTHON_PIPE_CREATED) {
delete_RT_to_nRT_signal(Python_handle);
PLC_state &= ~PLC_STATE_PYTHON_PIPE_CREATED;
/* Wait until PLC task stops */
void catch_signal(int sig)
// signal(SIGTERM, catch_signal);
signal(SIGINT, catch_signal);
printf("Got Signal %d\n",sig);
#define _startPLCLog(text) \
LogMessage(LOG_CRITICAL, mstr, sizeof(mstr));\
#define FO "Failed opening "
#define max_val(a,b) ((a>b)?a:b)
int startPLC(int argc,char **argv)
signal(SIGINT, catch_signal);
/* no memory swapping for that process */
mlockall(MCL_CURRENT | MCL_FUTURE);
/* memory initialization */
bzero(RT_to_nRT_signal_pool, sizeof(RT_to_nRT_signal_pool));
if(!(Debug_handle = create_RT_to_nRT_signal("Debug_pipe"))) goto error;
PLC_state |= PLC_STATE_DEBUG_PIPE_CREATED;
if(!(Python_handle = create_RT_to_nRT_signal("Python_pipe"))) goto error;
PLC_state |= PLC_STATE_PYTHON_PIPE_CREATED;
/* create WaitDebug_pipe */
if(!(WaitDebug_handle = create_RT_to_nRT_signal("WaitDebug_pipe"))) goto error;
PLC_state |= PLC_STATE_WAITDEBUG_PIPE_CREATED;
/* create WaitPython_pipe */
if(!(WaitPython_handle = create_RT_to_nRT_signal("WaitPython_pipe"))) goto error;
PLC_state |= PLC_STATE_WAITPYTHON_PIPE_CREATED;
/*** create PLC task ***/
if(rt_task_create(&PLC_task, "PLC_task", 0, 50, T_JOINABLE))
_startPLCLog("Failed creating PLC task");
PLC_state |= PLC_STATE_TASK_CREATED;
if(__init(argc,argv)) goto error;
if(rt_task_start(&PLC_task, &PLC_task_proc, NULL))
_startPLCLog("Failed starting PLC task");
static long debug_state = DEBUG_FREE;
int TryEnterDebugSection(void)
if(AtomicCompareExchange(
DEBUG_BUSY) == DEBUG_FREE){
AtomicCompareExchange( &debug_state, DEBUG_BUSY, DEBUG_FREE);
void LeaveDebugSection(void)
if(AtomicCompareExchange( &debug_state,
DEBUG_BUSY, DEBUG_FREE) == DEBUG_BUSY){
/* signal to NRT for wakeup */
send_RT_to_nRT_signal(Debug_handle, msg);
extern unsigned long __tick;
int WaitDebugData(unsigned long *tick)
if (PLC_shutdown) return -1;
/* Wait signal from PLC thread */
res = recv_RT_to_nRT_signal(WaitDebug_handle, &cmd);
if (res == 1 && cmd == DEBUG_PENDING_DATA){
/* Called by PLC thread when debug_publish finished
* This is supposed to unlock debugger thread in WaitDebugData*/
void InitiateDebugTransfer()
char msg = DEBUG_PENDING_DATA;
/* signal debugger thread it can read data */
send_RT_to_nRT_signal(WaitDebug_handle, msg);
int suspendDebug(int disable)
if (PLC_shutdown) return -1;
while(AtomicCompareExchange(
DEBUG_BUSY) != DEBUG_FREE &&
if(recv_RT_to_nRT_signal(Debug_handle, &cmd) != 1){
AtomicCompareExchange( &debug_state, DEBUG_BUSY, DEBUG_FREE);
AtomicCompareExchange( &debug_state, DEBUG_BUSY, DEBUG_FREE);
static long python_state = PYTHON_FREE;
int WaitPythonCommands(void)
if (PLC_shutdown) return -1;
/* Wait signal from PLC thread */
if(recv_RT_to_nRT_signal(WaitPython_handle, &cmd) == 1 && cmd==PYTHON_PENDING_COMMAND){
/* Called by PLC thread on each new python command*/
void UnBlockPythonCommands(void)
char msg = PYTHON_PENDING_COMMAND;
send_RT_to_nRT_signal(WaitPython_handle, msg);
return AtomicCompareExchange(
PYTHON_BUSY) == PYTHON_FREE;
char cmd = UNLOCK_PYTHON;
if (PLC_shutdown) return;
while(AtomicCompareExchange(
PYTHON_BUSY) != PYTHON_FREE &&
recv_RT_to_nRT_signal(Python_handle, &cmd);
if(AtomicCompareExchange(
PYTHON_FREE) == PYTHON_BUSY){
if(rt_task_self()){/*is that the real time task ?*/
char cmd = UNLOCK_PYTHON;
send_RT_to_nRT_signal(Python_handle, cmd);
}/* otherwise, no signaling from non real time */
} /* as plc does not wait for lock. */
int CheckRetainBuffer(void)
void ValidateRetainBuffer(void)
void InValidateRetainBuffer(void)
void Retain(unsigned int offset, unsigned int count, void *p)
void Remind(unsigned int offset, unsigned int count, void *p)