kk Show full post »
thiagoralves
I don’t know... I can’t see you program from the screenshot. What I can see is that, for some reason, the web server lost communication with the runtime
Quote 0 0
kk

The following are. CPP and. h files. They have no problems, mainly the main. CPP call problem. I want to control the GPIO port, but the main. CPP call seems to have some problems


jetsontk1.cpp:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include "custom_layer.h"
#include "jetsontk1.h"
#include "ladder.h"


int gpio_set_dir(unsigned int gpio, PIN_DIRECTION out_flag)
{
int fd;
char buf[MAX_BUF];

snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/direction", gpio);

fd = open(buf, O_WRONLY);
if (fd < 0) {
perror("gpio/direction");
return fd;
}

if (out_flag == OUTPUT_PIN)
write(fd, "out", 4);
else
write(fd, "in", 3);

close(fd);
return 0;
}

int TegraGPIOSetup()
{
int fd,len;
int i;
char buf[MAX_BUF];

fd = open(SYSFS_GPIO_DIR"/export", O_WRONLY);
if( fd < 0 ) {
perror("gpio/export");
return fd;
}

for( i = 0; i < MAX_GPIO; i++ ) {
len = snprintf(buf, sizeof(buf), "%d", GPIOBUfferPinMask[i]);
write(fd, buf, len);
}

close(fd);

for( i = 0; i < MAX_INPUT; i++) {
snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR"/gpio%d/value", inBufferPinMask[i]);

inSysFds[i] = open(buf, O_RDONLY);
if(inSysFds[i] < 0) {
perror("gpio/value");
}
}

for( i = 0; i < MAX_OUTPUT; i++) {
snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR"/gpio%d/value", outBufferPinMask[i]);

outSysFds[i] = open(buf, O_WRONLY);
if(outSysFds[i] < 0) {
perror("gpio/value");
}
}


}

void initializeHardware()
{

TegraGPIOSetup();
//piHiPri(99);

for(int i = 0; i < MAX_INPUT; i++ )
gpio_set_dir(inBufferPinMask[i], INPUT_PIN);
for(int i = 0; i < MAX_OUTPUT; i++ )
gpio_set_dir(outBufferPinMask[i], OUTPUT_PIN);

}

int digitalRead(int fd)
{
char ch;

read(fd, &ch, 1);

if(ch != '0'){
return 1;
}else{
return 0;
}
}

int digitalWrite(int fd, int value)
{
if(value == 0)
write(fd, "0", 2);
else
write(fd, "1", 2);

return 0;
}


void updateBuffersIn()
{
pthread_mutex_lock(&bufferLock); //lock mutex

//INPUT
for (int i = 0; i < MAX_INPUT; i++)
{
if (bool_input[i/8][i%8] != NULL)
{
*bool_input[i/8][i%8] = digitalRead(inSysFds[i]);
}
}

pthread_mutex_lock(&bufferLock); //lock mutex
}
void updateBuffersOut()
{
pthread_mutex_lock(&bufferLock); //lock mutex

//OUTPUT
for (int i = 0; i < MAX_OUTPUT; i++)
{
if (bool_output[i/8][i%8] != NULL)
{
digitalWrite(outSysFds[i], *bool_output[i/8][i%8]);
}
}

pthread_mutex_unlock(&bufferLock); //unlock mutex
}

jetsontk1.h:

#ifndef JETSONTK1_H_
#define JETSONTK1_H_

#define MAX_INPUT 4
#define MAX_OUTPUT 4
#define MAX_GPIO 8
#define SYSFS_GPIO_DIR "/sys/class/gpio"
#define MAX_BUF 64

enum PIN_DIRECTION{
INPUT_PIN=0,
OUTPUT_PIN=1
};


static int inSysFds [4] =
{
-1, -1, -1, -1,
};

static int outSysFds [4] =
{
-1, -1, -1, -1,
};

static int inBufferPinMask[MAX_INPUT] = { 178, 161, 162, 163 };
static int outBufferPinMask[MAX_OUTPUT] = { 171, 165, 166, 57 };
static int GPIOBUfferPinMask[MAX_GPIO] = { 178, 161, 162, 163, 171, 165, 166, 57
};

int digitalWrite(int fd, int value);
int digitalRead(int fd);
int TegraGPIOSetup();
int gpio_set_dir(unsigned int gpio, PIN_DIRECTION out_flag);

void updateBuffersIn();
void updateBuffersOut();
#endif

main.cpp:

#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <time.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include "jetsontk1.h"
#include "iec_types.h"
#include "ladder.h"

#define OPLC_CYCLE 50000000

extern int opterr;
//extern int common_ticktime__;
IEC_BOOL __DEBUG;

IEC_LINT cycle_counter = 0;
void init_bool_in_out_1();
static int tick = 0;
pthread_mutex_t bufferLock; //mutex for the internal buffers
pthread_mutex_t logLock; //mutex for the internal log
uint8_t run_openplc = 1; //Variable to control OpenPLC Runtime execution
unsigned char log_buffer[1000000]; //A very large buffer to store all logs
int log_index = 0;
int log_counter = 0;

//-----------------------------------------------------------------------------
// Helper function - Makes the running thread sleep for the ammount of time
// in milliseconds
//-----------------------------------------------------------------------------
void sleep_until(struct timespec *ts, int delay)
{
ts->tv_nsec += delay;
if(ts->tv_nsec >= 1000*1000*1000)
{
ts->tv_nsec -= 1000*1000*1000;
ts->tv_sec++;
}
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, ts, NULL);
}

//-----------------------------------------------------------------------------
// Helper function - Makes the running thread sleep for the ammount of time
// in milliseconds
//-----------------------------------------------------------------------------
void sleepms(int milliseconds)
{
struct timespec ts;
ts.tv_sec = milliseconds / 1000;
ts.tv_nsec = (milliseconds % 1000) * 1000000;
nanosleep(&ts, NULL);
}

//-----------------------------------------------------------------------------
// Helper function - Logs messages and print them on the console
//-----------------------------------------------------------------------------
void log(unsigned char *logmsg)
{
pthread_mutex_lock(&logLock); //lock mutex
printf("%s", logmsg);
for (int i = 0; logmsg[i] != '\0'; i++)
{
log_buffer[log_index] = logmsg[i];
log_index++;
log_buffer[log_index] = '\0';
}

log_counter++;
if (log_counter >= 1000)
{
/*Store current log on a file*/
log_counter = 0;
log_index = 0;
}
pthread_mutex_unlock(&logLock); //unlock mutex
}

//-----------------------------------------------------------------------------
// Interactive Server Thread. Creates the server to listen to commands on
// localhost
//-----------------------------------------------------------------------------
void *interactiveServerThread(void *arg)
{
startInteractiveServer(43628);
}

//-----------------------------------------------------------------------------
// Verify if pin is present in one of the ignored vectors
//-----------------------------------------------------------------------------
bool pinNotPresent(int *ignored_vector, int vector_size, int pinNumber)
{
for (int i = 0; i < vector_size; i++)
{
if (ignored_vector[i] == pinNumber)
return false;
}

return true;
}
/*
//-----------------------------------------------------------------------------
// Disable all outputs
//--------------------------------------------------------------------------
void disableOutputs()
{
//Disable digital outputs
for (int i = 0; i < BUFFER_SIZE; i++)
{
for (int j = 0; j < 8; j++)
{
if (bool_output[i][j] != NULL) *bool_output[i][j] = 0;
}
}

//Disable byte outputs
for (int i = 0; i < BUFFER_SIZE; i++)
{
if (byte_output[i] != NULL) *byte_output[i] = 0;
}

//Disable analog outputs
for (int i = 0; i < BUFFER_SIZE; i++)
{
if (int_output[i] != NULL) *int_output[i] = 0;
}
}*/

void init_bool_in_out_1()
{

for (int i = 0; i < 8; i++)
{
if (bool_output[i/8][i%8] != NULL) *bool_output[i/8][i%8] = 1;
}
for (int i = 0; i < 8; i++)
{
if (bool_input[i/8][i%8] != NULL) *bool_input[i/8][i%8] = 1;
}
}
//-----------------------------------------------------------------------------
// Special Functions
//-----------------------------------------------------------------------------
void handleSpecialFunctions()
{
//current time [%ML1024]
struct tm *current_time;
time_t rawtime;

tzset();
time(&rawtime);
current_time = localtime(&rawtime);

rawtime = rawtime - timezone;
if (current_time->tm_isdst > 0) rawtime = rawtime + 3600;

if (special_functions[0] != NULL) *special_functions[0] = rawtime;

//number of cycles [%ML1025]
cycle_counter++;
if (special_functions[1] != NULL) *special_functions[1] = cycle_counter;

//comm error counter [%ML1026]
/* Implemented in modbus_master.cpp */

//insert other special functions below
}

int main(int argc,char **argv)
{
unsigned char log_msg[1000];
sprintf(log_msg, "OpenPLC Runtime starting...\n");
log(log_msg);

//======================================================
// PLC INITIALIZATION
//======================================================
time(&start_time);
pthread_t interactive_thread;
pthread_create(&interactive_thread, NULL, interactiveServerThread, NULL);
config_init__();
glueVars();

//======================================================
// MUTEX INITIALIZATION
//======================================================
if (pthread_mutex_init(&bufferLock, NULL) != 0)
{
printf("Mutex init failed\n");
exit(1);
}

//======================================================
// HARDWARE INITIALIZATION
//======================================================
//int digitalRead(int fd);
//int digitalWrite(int fd,int value);
//void TegraGPIOSetup();
//int gpio_set_dir(unsigned int gpio, unsigned int out_flag);
//leep_thread(int milliseconds);

initializeHardware();
initializeMB();
initCustomLayer();
updateBuffersIn();
updateCustomIn();
updateBuffersOut();
updateCustomOut();


//======================================================
// PERSISTENT STORAGE INITIALIZATION
//======================================================
//readPersistentStorage();
//pthread_t persistentThread;
//pthread_create(&persistentThread, NULL, persistentStorage, NULL);

#ifdef __linux__
//======================================================
// REAL-TIME INITIALIZATION
//======================================================
// Set our thread to real time priority
struct sched_param sp;
sp.sched_priority = 30;
printf("Setting main thread priority to RT\n");
if(pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp))
{
printf("WARNING: Failed to set main thread to real-time priority\n");
}

// Lock memory to ensure no swapping is done.
printf("Locking main thread memory\n");
if(mlockall(MCL_FUTURE|MCL_CURRENT))
{
printf("WARNING: Failed to lock memory\n");
}
#endif

//gets the starting point for the clock
printf("Getting current time\n");
struct timespec timer_start;
clock_gettime(CLOCK_MONOTONIC, &timer_start);
//disableOutputs();
init_bool_in_out_1();
//======================================================
// MAIN LOOP
//======================================================
while(run_openplc)
{
//make sure the buffer pointers are correct and
//attached to the user variables
glueVars();
//sleep_thread(10); //wait for the input data received
updateBuffersIn(); //read input image

pthread_mutex_lock(&bufferLock); //lock mutex
//updateCustomIn();
//updateBuffersIn_MB(); //update input image table with data from slave
//devices
//handleSpecialFunctions();
config_run__(tick++); // execute plc program logic
//updateCustomOut();
//updateBuffersOut_MB(); //update slave devices with data from the outpuu
//t image table
//updateBuffersOut();
pthread_mutex_unlock(&bufferLock); //unlock mutex

updateBuffersOut(); //write output image

//updateTime();

sleep_until(&timer_start, common_ticktime__);
}

//======================================================
// SHUTTING DOWN OPENPLC RUNTIME
//======================================================
/*
pthread_join(interactive_thread, NULL);
printf("Disabling outputs\n");
disableOutputs();
updateCustomOut();
updateBuffersOut();
printf("Shutting down OpenPLC Runtime...\n");
exit(0);
*/
}
Quote 0 0
thiagoralves
You're stuck forever because you're locking the buffer mutex and never unlocking it on the void updateBuffersIn() function.

Also, next time you paste code, please use the code feature on the forum. It is really hard to read your code pasted here with no indentation or formatting.
Quote 0 0
kk
Okay, here's my code. You can take a look and see if there's any problem. Thank you

jetsontk1.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include "custom_layer.h"
#include "jetsontk1.h"
#include "ladder.h"

int gpio_set_dir(unsigned int gpio, PIN_DIRECTION out_flag)
{
        int fd;
        char buf[MAX_BUF];
        snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR  "/gpio%d/direction", gpio);
        fd = open(buf, O_WRONLY);
        if (fd < 0) {
                perror("gpio/direction");
                return fd;
        }
        if (out_flag == OUTPUT_PIN)
                write(fd, "out", 4);
        else
                write(fd, "in", 3);
        close(fd);
        return 0;
}
int TegraGPIOSetup()
{
        int fd,len;
        int i;
        char buf[MAX_BUF];
        fd = open(SYSFS_GPIO_DIR"/export", O_WRONLY);
        if( fd < 0 😉 {
                perror("gpio/export");
                return fd;
        }
        for( i = 0; i < MAX_GPIO; i++ 😉 {
                len = snprintf(buf, sizeof(buf), "%d", GPIOBUfferPinMask[i]);
                write(fd, buf, len);
        }
        close(fd);
        for( i = 0; i < MAX_INPUT; i++) {
snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR"/gpio%d/value", inBufferPinMask[i]);
                inSysFds[i] = open(buf, O_RDONLY);
                if(inSysFds[i] < 0) {
                        perror("gpio/value");
                }
        }
        for( i = 0; i < MAX_OUTPUT; i++) {
snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR"/gpio%d/value", outBufferPinMask[i]);
                outSysFds[i] = open(buf, O_WRONLY);
                if(outSysFds[i] < 0) {
                        perror("gpio/value");
                }
        }

}
void initializeHardware()
{
        TegraGPIOSetup();
        //piHiPri(99);
        for(int i = 0; i < MAX_INPUT; i++ 😉
                gpio_set_dir(inBufferPinMask[i], INPUT_PIN);
        for(int i = 0; i < MAX_OUTPUT; i++ 😉
                gpio_set_dir(outBufferPinMask[i], OUTPUT_PIN);
}
int digitalRead(int fd)
{
        char ch;
        read(fd, &ch, 1);
        if(ch != '0'){
                return 1;
        }else{
                return 0;
        }
}
int digitalWrite(int fd, int value)
{
        if(value == 0)
                write(fd, "0", 2);
        else
                write(fd, "1", 2);
        return 0;
}

void updateBuffersIn()
{
        pthread_mutex_lock(&bufferLock); //lock mutex
        //INPUT
        for (int i = 0; i < MAX_INPUT; i++)
        {
                if (bool_input[i/8][i%8] != NULL)
                {
                        *bool_input[i/8][i%8] = digitalRead(inSysFds[i]);
                }
        }
        pthread_mutex_unlock(&bufferLock); //unlock mutex
}
void updateBuffersOut()
{
        pthread_mutex_lock(&bufferLock); //lock mutex
        //OUTPUT
        for (int i = 0; i < MAX_OUTPUT; i++)
        {
                if (bool_output[i/8][i%8] != NULL)
                {
                        digitalWrite(outSysFds[i], *bool_output[i/8][i%8]);
                }
        }
        pthread_mutex_unlock(&bufferLock); //unlock mutex
}

jetsontk1.h:
#ifndef JETSONTK1_H_
#define JETSONTK1_H_
#define MAX_INPUT 4
#define MAX_OUTPUT 4
#define MAX_GPIO 8
#define SYSFS_GPIO_DIR "/sys/class/gpio"
#define MAX_BUF 64
enum PIN_DIRECTION{
        INPUT_PIN=0,
        OUTPUT_PIN=1
};

static int inSysFds [4] =
{
        -1, -1, -1, -1,
};
static int outSysFds [4] =
{
        -1, -1, -1, -1,
};
static int inBufferPinMask[MAX_INPUT] = { 178, 161, 162, 163 };
static int outBufferPinMask[MAX_OUTPUT] = { 171, 165, 166, 57 };
static int GPIOBUfferPinMask[MAX_GPIO] = { 178, 161, 162, 163, 171, 165, 166, 57
 };
int digitalWrite(int fd, int value);
int digitalRead(int fd);
int TegraGPIOSetup();
int gpio_set_dir(unsigned int gpio, PIN_DIRECTION out_flag);
void updateBuffersIn();
void updateBuffersOut();
#endif

main.cpp:
#include <stdio.h>
#include <string.h>
#include <pthread.h>                                                            
#include <time.h> 
#include <signal.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/mman.h>
#include "jetsontk1.h"
#include "iec_types.h"
#include "ladder.h" 
      
#define OPLC_CYCLE          50000000                                            
extern int opterr; 
//extern int common_ticktime__;
IEC_BOOL __DEBUG;
    
IEC_LINT cycle_counter = 0;
void init_bool_in_out_1();
static int tick = 0;
pthread_mutex_t bufferLock; //mutex for the internal buffers                    
pthread_mutex_t logLock; //mutex for the internal log                           
uint8_t run_openplc = 1; //Variable to control OpenPLC Runtime execution
unsigned char log_buffer[1000000]; //A very large buffer to store all logs
int log_index = 0;
int log_counter = 0;
//-----------------------------------------------------------------------------
// Helper function - Makes the running thread sleep for the ammount of time
// in milliseconds
//-----------------------------------------------------------------------------
void sleep_until(struct timespec *ts, int delay)
{
    ts->tv_nsec += delay;
    if(ts->tv_nsec >= 1000*1000*1000)
    {
        ts->tv_nsec -= 1000*1000*1000;
        ts->tv_sec++;
    }
    clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, ts,  NULL);
}
//-----------------------------------------------------------------------------
// Helper function - Makes the running thread sleep for the ammount of time
// in milliseconds
//-----------------------------------------------------------------------------
void sleepms(int milliseconds)
{
        struct timespec ts;
        ts.tv_sec = milliseconds / 1000;
        ts.tv_nsec = (milliseconds % 1000) * 1000000;
        nanosleep(&ts, NULL);
}
//-----------------------------------------------------------------------------
// Helper function - Logs messages and print them on the console
//-----------------------------------------------------------------------------
void log(unsigned char *logmsg)
{
    pthread_mutex_lock(&logLock); //lock mutex
    printf("%s", logmsg);
    for (int i = 0; logmsg[i] != '\0'; i++)
    {
        log_buffer[log_index] = logmsg[i];
        log_index++;
        log_buffer[log_index] = '\0';
    }
    log_counter++;
    if (log_counter >= 1000)
    {
        /*Store current log on a file*/
        log_counter = 0;
        log_index = 0;
    }
    pthread_mutex_unlock(&logLock); //unlock mutex
}
//-----------------------------------------------------------------------------
// Interactive Server Thread. Creates the server to listen to commands on
// localhost
//-----------------------------------------------------------------------------
void *interactiveServerThread(void *arg)
{
    startInteractiveServer(43628);
}
//-----------------------------------------------------------------------------
// Verify if pin is present in one of the ignored vectors
//-----------------------------------------------------------------------------
bool pinNotPresent(int *ignored_vector, int vector_size, int pinNumber)
{
    for (int i = 0; i < vector_size; i++)
    {
        if (ignored_vector[i] == pinNumber)
            return false;
    }
    return true;
}
void init_bool_in_out_1()
{
        for (int i = 0; i < 8; i++)
        {
                if (bool_output[i/8][i%8] != NULL) *bool_output[i/8][i%8] = 1;
        }
    for (int i = 0; i < 8; i++)
    {
        if (bool_input[i/8][i%8] != NULL) *bool_input[i/8][i%8] = 1;
    }
}
//-----------------------------------------------------------------------------
// Special Functions
//-----------------------------------------------------------------------------
void handleSpecialFunctions()
{
    //current time [%ML1024]
    struct tm *current_time;
    time_t rawtime;
    tzset();
    time(&rawtime);
    current_time = localtime(&rawtime);
    rawtime = rawtime - timezone;
    if (current_time->tm_isdst > 0) rawtime = rawtime + 3600;
    if (special_functions[0] != NULL) *special_functions[0] = rawtime;
    //number of cycles [%ML1025]
    cycle_counter++;
    if (special_functions[1] != NULL) *special_functions[1] = cycle_counter;
    //comm error counter [%ML1026]
    /* Implemented in modbus_master.cpp */
    //insert other special functions below
}
int main(int argc,char **argv)
{
    unsigned char log_msg[1000];
    sprintf(log_msg, "OpenPLC Runtime starting...\n");
    log(log_msg);
    //======================================================
    //                 PLC INITIALIZATION
    //======================================================
    time(&start_time);
    pthread_t interactive_thread;
    pthread_create(&interactive_thread, NULL, interactiveServerThread, NULL);
    config_init__();
    glueVars();
    //======================================================
    //               MUTEX INITIALIZATION
    //======================================================
    if (pthread_mutex_init(&bufferLock, NULL) != 0)
    {
        printf("Mutex init failed\n");
        exit(1);
    }
    //======================================================
    //              HARDWARE INITIALIZATION
    //======================================================
    initializeHardware();
    initializeMB();
    initCustomLayer();
    updateBuffersIn();
    updateCustomIn();
    updateBuffersOut();
    updateCustomOut();
    //======================================================
    //          PERSISTENT STORAGE INITIALIZATION
    //======================================================
    //readPersistentStorage();
    //pthread_t persistentThread;
    //pthread_create(&persistentThread, NULL, persistentStorage, NULL);
#ifdef __linux__
    //======================================================
    //              REAL-TIME INITIALIZATION
    //======================================================
    // Set our thread to real time priority
    struct sched_param sp;
    sp.sched_priority = 30;
    printf("Setting main thread priority to RT\n");
    if(pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp))
    {
        printf("WARNING: Failed to set main thread to real-time priority\n");
    }
    // Lock memory to ensure no swapping is done.
    printf("Locking main thread memory\n");
    if(mlockall(MCL_FUTURE|MCL_CURRENT))
    {
        printf("WARNING: Failed to lock memory\n");
    }
#endif
        //gets the starting point for the clock
        printf("Getting current time\n");
        struct timespec timer_start;
        clock_gettime(CLOCK_MONOTONIC, &timer_start);
        //disableOutputs();
        init_bool_in_out_1();
        //======================================================
        //                    MAIN LOOP
        //======================================================
        while(run_openplc)
        {
                //make sure the buffer pointers are correct and
                //attached to the user variables
                glueVars();
                //sleep_thread(10); //wait for the input data received
                updateBuffersIn(); //read input image
                pthread_mutex_lock(&bufferLock); //lock mutex
                //updateCustomIn();
     //updateBuffersIn_MB(); //update input image table with data from slave  
//devices
        //handleSpecialFunctions();
                config_run__(tick++); // execute plc program logic
                //updateCustomOut();
     //updateBuffersOut_MB(); //update slave devices with data from the outpuu
//t image table
                //updateBuffersOut();
                pthread_mutex_unlock(&bufferLock); //unlock mutex
                updateBuffersOut(); //write output image
                //updateTime();
                sleep_until(&timer_start, common_ticktime__);
        }
    //======================================================
        //             SHUTTING DOWN OPENPLC RUNTIME
        //======================================================
/*        
    pthread_join(interactive_thread, NULL);
    printf("Disabling outputs\n");
    disableOutputs();
    updateCustomOut();
    updateBuffersOut();
    printf("Shutting down OpenPLC Runtime...\n");
    exit(0);
*/
}

Quote 0 0
thiagoralves
Your code seems fine now, although you have commented out several OpenPLC functions that might make it not work as it should (like updateTime not running will break timers and other logical structures that depends on current time). That being said, I don’t have your board to test the code and make sure it is working correctly. All I can do is read the code and point out the more obvious mistakes. 
Quote 0 0