Error when compiling HAL component: undefined symbol: pinMode

More
05 Dec 2023 10:59 #287250 by MakerYang
When using wiringPi in the HAL component, it seems that the relevant functions cannot be found, even though wiringPi has been properly installed. The error message is as follows:
...
DISPLAY=halui
COORDINATES=XYZ
KINEMATICS=trivkins coordinates=XYZ
Starting LinuxCNC...
Starting LinuxCNC server program: linuxcncsvr
Loading Real Time OS, RTAPI, and HAL_LIB modules
Starting LinuxCNC IO program: io
linuxcnc TPMOD=tpmod HOMEMOD=homemod EMCMOT=motmod
Found file(REL): ./machine.hal
Shutting down and cleaning up LinuxCNC...
Removing HAL_LIB, RTAPI, and Real Time OS modules
Removing NML shared memory segments

Debug file information:
Can not find -sec DISPLAY -var INTRO_GRAPHIC -num 1
Can not find -sec DISPLAY -var INTRO_TIME -num 1
Note: Using POSIX realtime
armcnc_driver: dlopen: /usr/lib/linuxcnc/modules/armcnc_driver.so: undefined symbol: pinMode
./machine.hal:6: waitpid failed /usr/bin/rtapi_app armcnc_driver
./machine.hal:6: /usr/bin/rtapi_app exited without becoming ready
./machine.hal:6: insmod for armcnc_driver failed, returned -1
12046
Stopping realtime threads
Unloading hal components
Note: Using POSIX realtime
...

The source code of armcnc_driver.c is as follows:
/**
 ******************************************************************************
 * @file    armcnc_driver.c
 * @author  ARMCNC site:www.armcnc.net github:armcnc.github.io
 ******************************************************************************
 */

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wiringPi.h>

#include "armcnc_driver.h"
#include "rtapi.h"
#include "rtapi_app.h"
#include "rtapi_math.h"
#include "hal.h"

#define MAX_PINS 40
#define MAX_INI_LINE_LENGTH 255
#define MAX_INI_VALUE_LENGTH 10

static int component_id;
hal_bit_t **port_data;

typedef struct {
    char ESTOP_PIN[MAX_INI_VALUE_LENGTH][MAX_INI_LINE_LENGTH];
    char SPINDLE_ENABLE_PIN[MAX_INI_VALUE_LENGTH][MAX_INI_LINE_LENGTH];
    char SPINDLE_PWM_PIN[MAX_INI_VALUE_LENGTH][MAX_INI_LINE_LENGTH];
    char X_HOME_PIN[MAX_INI_VALUE_LENGTH][MAX_INI_LINE_LENGTH];
    char Y_HOME_PIN[MAX_INI_VALUE_LENGTH][MAX_INI_LINE_LENGTH];
    char Z_HOME_PIN[MAX_INI_VALUE_LENGTH][MAX_INI_LINE_LENGTH];
    char A_HOME_PIN[MAX_INI_VALUE_LENGTH][MAX_INI_LINE_LENGTH];
    char B_HOME_PIN[MAX_INI_VALUE_LENGTH][MAX_INI_LINE_LENGTH];
    char C_HOME_PIN[MAX_INI_VALUE_LENGTH][MAX_INI_LINE_LENGTH];
} INI_RESULT;

static INI_RESULT ini_data = {0};

#ifdef RTAPI
MODULE_AUTHOR("ARMCNC");
MODULE_DESCRIPTION("Driver for ARMCNC");
MODULE_LICENSE("GPL");
#endif

int read_ini_file(const char *filename, INI_RESULT *result) {

    FILE *file = fopen(filename, "r");
    if (!file) {
        rtapi_print_msg(RTAPI_MSG_ERR, "[error]: INI_RESULT\n");
        return -1;
    }

    char line[MAX_INI_LINE_LENGTH];
    char key[MAX_INI_LINE_LENGTH];
    char val[MAX_INI_LINE_LENGTH];

    while (fgets(line, MAX_INI_LINE_LENGTH, file) != NULL) {
        if (line[0] == '#' || line[0] == ';' || line[0] == '\n') continue;
        if (sscanf(line, "%[^=] = %s", key, val) == 2) {
            if (strcmp(key, "ESTOP_PIN") == 0 && strcmp(val, "") != 0) {
                char *token;
                int i = 0;
                token = strtok(val, " ");
                while (token != NULL && i < MAX_INI_VALUE_LENGTH) {
                    strncpy(result->ESTOP_PIN[i], token, MAX_INI_LINE_LENGTH);
                    result->ESTOP_PIN[i][MAX_INI_LINE_LENGTH - 1] = '\0';
                    token = strtok(NULL, " ");
                    i++;
                }
            }
            if (strcmp(key, "SPINDLE_ENABLE_PIN") == 0 && strcmp(val, "") != 0) {
                char *token;
                int i = 0;
                token = strtok(val, " ");
                while (token != NULL && i < MAX_INI_VALUE_LENGTH) {
                    strncpy(result->SPINDLE_ENABLE_PIN[i], token, MAX_INI_LINE_LENGTH);
                    result->SPINDLE_ENABLE_PIN[i][MAX_INI_LINE_LENGTH - 1] = '\0';
                    token = strtok(NULL, " ");
                    i++;
                }
            }
            if (strcmp(key, "SPINDLE_PWM_PIN") == 0 && strcmp(val, "") != 0) {
                char *token;
                int i = 0;
                token = strtok(val, " ");
                while (token != NULL && i < MAX_INI_VALUE_LENGTH) {
                    strncpy(result->SPINDLE_PWM_PIN[i], token, MAX_INI_LINE_LENGTH);
                    result->SPINDLE_PWM_PIN[i][MAX_INI_LINE_LENGTH - 1] = '\0';
                    token = strtok(NULL, " ");
                    i++;
                }
            }
            if (strcmp(key, "X_HOME_PIN") == 0 && strcmp(val, "") != 0) {
                char *token;
                int i = 0;
                token = strtok(val, " ");
                while (token != NULL && i < MAX_INI_VALUE_LENGTH) {
                    strncpy(result->X_HOME_PIN[i], token, MAX_INI_LINE_LENGTH);
                    result->X_HOME_PIN[i][MAX_INI_LINE_LENGTH - 1] = '\0';
                    token = strtok(NULL, " ");
                    i++;
                }
            }
            if (strcmp(key, "Y_HOME_PIN") == 0 && strcmp(val, "") != 0) {
                char *token;
                int i = 0;
                token = strtok(val, " ");
                while (token != NULL && i < MAX_INI_VALUE_LENGTH) {
                    strncpy(result->Y_HOME_PIN[i], token, MAX_INI_LINE_LENGTH);
                    result->Y_HOME_PIN[i][MAX_INI_LINE_LENGTH - 1] = '\0';
                    token = strtok(NULL, " ");
                    i++;
                }
            }
            if (strcmp(key, "Z_HOME_PIN") == 0 && strcmp(val, "") != 0) {
                char *token;
                int i = 0;
                token = strtok(val, " ");
                while (token != NULL && i < MAX_INI_VALUE_LENGTH) {
                    strncpy(result->Z_HOME_PIN[i], token, MAX_INI_LINE_LENGTH);
                    result->Z_HOME_PIN[i][MAX_INI_LINE_LENGTH - 1] = '\0';
                    token = strtok(NULL, " ");
                    i++;
                }
            }
            if (strcmp(key, "A_HOME_PIN") == 0 && strcmp(val, "") != 0) {
                char *token;
                int i = 0;
                token = strtok(val, " ");
                while (token != NULL && i < MAX_INI_VALUE_LENGTH) {
                    strncpy(result->A_HOME_PIN[i], token, MAX_INI_LINE_LENGTH);
                    result->A_HOME_PIN[i][MAX_INI_LINE_LENGTH - 1] = '\0';
                    token = strtok(NULL, " ");
                    i++;
                }
            }
            if (strcmp(key, "B_HOME_PIN") == 0 && strcmp(val, "") != 0) {
                char *token;
                int i = 0;
                token = strtok(val, " ");
                while (token != NULL && i < MAX_INI_VALUE_LENGTH) {
                    strncpy(result->B_HOME_PIN[i], token, MAX_INI_LINE_LENGTH);
                    result->B_HOME_PIN[i][MAX_INI_LINE_LENGTH - 1] = '\0';
                    token = strtok(NULL, " ");
                    i++;
                }
            }
            if (strcmp(key, "C_HOME_PIN") == 0 && strcmp(val, "") != 0) {
                char *token;
                int i = 0;
                token = strtok(val, " ");
                while (token != NULL && i < MAX_INI_VALUE_LENGTH) {
                    strncpy(result->C_HOME_PIN[i], token, MAX_INI_LINE_LENGTH);
                    result->C_HOME_PIN[i][MAX_INI_LINE_LENGTH - 1] = '\0';
                    token = strtok(NULL, " ");
                    i++;
                }
            }
        }
    }

    fclose(file);
    return 0;
}

static void gpio_write(void *arg, long period)
{
     int n;
}

static void gpio_read(void *arg, long period)
{
     int n;
     for (n = 0; n < MAX_PINS; n++) {
        *(port_data[n]) = 0;
     }
}

int rtapi_app_main(void)
{
    rtapi_print_msg(RTAPI_MSG_INFO, "armcnc_driver...\n");

    const char* env_var = "MACHINE_PATH";
    char* env_value = getenv(env_var);
    int retval = 0;

    if (!env_value || strcmp(env_value, "") == 0) {
        rtapi_print_msg(RTAPI_MSG_ERR, "[error]: MACHINE_PATH\n");
        return -1;
    }

    char filePath[1024];
    snprintf(filePath, sizeof(filePath), "/opt/armcnc/configs/%s/machine.user", env_value);
    if(!read_ini_file(filePath, &ini_data)){
        rtapi_print_msg(RTAPI_MSG_ERR, "[error]: read_ini_file\n");
        return -1;
    }

    if (wiringPiSetup() == -1){
        rtapi_print_msg(RTAPI_MSG_ERR, "[error]: wiringPiSetup\n");
        return -1;
    }

    component_id = hal_init("armcnc_driver");
    if (component_id < 0) {
        rtapi_print_msg(RTAPI_MSG_ERR, "[error]: component_id\n");
        return -1;
    }

    port_data = malloc(MAX_PINS * sizeof(hal_bit_t *));

    retval = hal_pin_bit_newf(ini_data.ESTOP_PIN[2] == "IN" ? HAL_IN : HAL_OUT, &port_data[atoi(ini_data.ESTOP_PIN[1])], component_id, ini_data.ESTOP_PIN[0]);
    if (retval < 0) {
        rtapi_print_msg(RTAPI_MSG_ERR, "[error]: ESTOP_PIN\n");
        hal_exit(component_id);
        return -1;
    }
    pinMode(atoi(ini_data.ESTOP_PIN[1]), ini_data.ESTOP_PIN[2] == "IN" ? INPUT : OUTPUT);

    retval = hal_pin_bit_newf(ini_data.SPINDLE_ENABLE_PIN[2] == "IN" ? HAL_IN : HAL_OUT, &port_data[atoi(ini_data.SPINDLE_ENABLE_PIN[1])], component_id, ini_data.SPINDLE_ENABLE_PIN[0]);
    if (retval < 0) {
        rtapi_print_msg(RTAPI_MSG_ERR, "[error]: SPINDLE_ENABLE_PIN\n");
        hal_exit(component_id);
        return -1;
    }
    pinMode(atoi(ini_data.SPINDLE_ENABLE_PIN[1]), ini_data.SPINDLE_ENABLE_PIN[2] == "IN" ? INPUT : OUTPUT);

    retval = hal_pin_bit_newf(ini_data.SPINDLE_PWM_PIN[2] == "IN" ? HAL_IN : HAL_OUT, &port_data[atoi(ini_data.SPINDLE_PWM_PIN[1])], component_id, ini_data.SPINDLE_PWM_PIN[0]);
    if (retval < 0) {
        rtapi_print_msg(RTAPI_MSG_ERR, "[error]: SPINDLE_PWM_PIN\n");
        hal_exit(component_id);
        return -1;
    }
    pinMode(atoi(ini_data.SPINDLE_PWM_PIN[1]), ini_data.SPINDLE_PWM_PIN[2] == "IN" ? INPUT : OUTPUT);

    retval = hal_pin_bit_newf(ini_data.X_HOME_PIN[2] == "IN" ? HAL_IN : HAL_OUT, &port_data[atoi(ini_data.X_HOME_PIN[1])], component_id, ini_data.X_HOME_PIN[0]);
    if (retval < 0) {
        rtapi_print_msg(RTAPI_MSG_ERR, "[error]: X_HOME_PIN\n");
        hal_exit(component_id);
        return -1;
    }
    pinMode(atoi(ini_data.X_HOME_PIN[1]), ini_data.X_HOME_PIN[2] == "IN" ? INPUT : OUTPUT);

    retval = hal_pin_bit_newf(ini_data.Y_HOME_PIN[2] == "IN" ? HAL_IN : HAL_OUT, &port_data[atoi(ini_data.Y_HOME_PIN[1])], component_id, ini_data.Y_HOME_PIN[0]);
    if (retval < 0) {
        rtapi_print_msg(RTAPI_MSG_ERR, "[error]: Y_HOME_PIN\n");
        hal_exit(component_id);
        return -1;
    }
    pinMode(atoi(ini_data.Y_HOME_PIN[1]), ini_data.Y_HOME_PIN[2] == "IN" ? INPUT : OUTPUT);

    retval = hal_pin_bit_newf(ini_data.Z_HOME_PIN[2] == "IN" ? HAL_IN : HAL_OUT, &port_data[atoi(ini_data.Z_HOME_PIN[1])], component_id, ini_data.Z_HOME_PIN[0]);
    if (retval < 0) {
        rtapi_print_msg(RTAPI_MSG_ERR, "[error]: Z_HOME_PIN\n");
        hal_exit(component_id);
        return -1;
    }
    pinMode(atoi(ini_data.Z_HOME_PIN[1]), ini_data.Z_HOME_PIN[2] == "IN" ? INPUT : OUTPUT);

    retval = hal_pin_bit_newf(ini_data.A_HOME_PIN[2] == "IN" ? HAL_IN : HAL_OUT, &port_data[atoi(ini_data.A_HOME_PIN[1])], component_id, ini_data.A_HOME_PIN[0]);
    if (retval < 0) {
        rtapi_print_msg(RTAPI_MSG_ERR, "[error]: A_HOME_PIN\n");
        hal_exit(component_id);
        return -1;
    }
    pinMode(atoi(ini_data.A_HOME_PIN[1]), ini_data.A_HOME_PIN[2] == "IN" ? INPUT : OUTPUT);

    retval = hal_pin_bit_newf(ini_data.B_HOME_PIN[2] == "IN" ? HAL_IN : HAL_OUT, &port_data[atoi(ini_data.B_HOME_PIN[1])], component_id, ini_data.B_HOME_PIN[0]);
    if (retval < 0) {
        rtapi_print_msg(RTAPI_MSG_ERR, "[error]: B_HOME_PIN\n");
        hal_exit(component_id);
        return -1;
    }
    pinMode(atoi(ini_data.B_HOME_PIN[1]), ini_data.B_HOME_PIN[2] == "IN" ? INPUT : OUTPUT);

    retval = hal_pin_bit_newf(ini_data.C_HOME_PIN[2] == "IN" ? HAL_IN : HAL_OUT, &port_data[atoi(ini_data.C_HOME_PIN[1])], component_id, ini_data.C_HOME_PIN[0]);
    if (retval < 0) {
        rtapi_print_msg(RTAPI_MSG_ERR, "[error]: C_HOME_PIN\n");
        hal_exit(component_id);
        return -1;
    }
    pinMode(atoi(ini_data.C_HOME_PIN[1]), ini_data.C_HOME_PIN[2] == "IN" ? INPUT : OUTPUT);

    retval = hal_export_funct("gpio.write", gpio_write, 0, 0, 0, component_id);
    if (retval < 0) {
        rtapi_print_msg(RTAPI_MSG_ERR, "[error]: gpio.write\n");
        hal_exit(component_id);
        return -1;
    }

    retval = hal_export_funct("gpio.read", gpio_read, 0, 0, 0, component_id);
    if (retval < 0) {
        rtapi_print_msg(RTAPI_MSG_ERR, "[error]: gpio.read\n");
        hal_exit(component_id);
        return -1;
    }

    hal_ready(component_id);
    return 0;
}

void rtapi_app_exit(void)
{
    hal_exit(component_id);
}

After trying to compile using the command below, the same error occurs.
sudo halcompile --install --userspace armcnc_driver.c --extra-compile-args="-I/usr/local/include" --extra-link-args="-L/usr/local/lib -lwiringPi -lwiringPiDev -lpthread -lm -lcrypt -lrt"

Please Log in or Create an account to join the conversation.

More
05 Dec 2023 23:22 #287323 by smc.collins
AFAIK , you don't use halcompile to build core components of linuxcnc. Halcompile is specifically meant for build hal components afaik. I could be wrong.
linuxcnc.org/docs/html/man/man1/halcompile.1.html
The following user(s) said Thank You: MakerYang

Please Log in or Create an account to join the conversation.

More
06 Dec 2023 02:20 #287326 by MakerYang
My mistake occurred when compiling a custom HAL real-time component, and the link you provided also indicates that it supports C files.

Please Log in or Create an account to join the conversation.

More
06 Dec 2023 06:56 #287333 by rodw
What it says is it preprocesses .comp files to .c files.
Comp files are a mix of C and Python to allow documents (man files) to be created in the one file. Plus it simplifies creating the C files for a component via some scripting.

Halcomp is used to create some  modules (eg. see homecomp.comp which allows building a custom homing module) but there is  support built into the core to allow this to be done.

Please Log in or Create an account to join the conversation.

Time to create page: 0.263 seconds
Powered by Kunena Forum