Skip to content
Snippets Groups Projects
Select Git revision
  • ae973ff360738c94a4c73965c32f7b09dad5cc02
  • main default protected
2 results

main.c

Blame
  • main.c 8.06 KiB
    /*-----------------------------------------------------------------------------
     *  File: main.c
     *
     *  This file is part of Sensapex smcp1_proxy codebase.
     *
     *  Created by Veli-Matti Kananen
     *  Copyright (c) 2023-2024 Sensapex Oy. All rights reserved.
     *---------------------------------------------------------------------------*/
    
    #include "executor.h"
    #include "functions.h"
    #include "misc.h"
    #include "smcp1.h"
    #include "tmcl.h"
    #include <assert.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <signal.h>
    #include <sys/time.h>
    
    #define DEFAULT_SERIAL_PORT "/dev/ttyACM0"
    #define DEFAULT_UDP_ADDRESS SMCP1_BROADCAST_ADDR
    #define DEFAULT_UDP_PORT SMCP1_DEF_UDP_PORT
    
    struct sigaction sa;
    
    pthread_t threadUdp;
    pthread_t threadExecComm;
    pthread_t threadExec0;
    pthread_t threadExec1;
    pthread_t threadExec2;
    pthread_t threadExec3;
    
    static void printUsage();
    static void heartBeatHandler(int signum);
    static mcu_error initThreads();
    
    int main(int argc, char *argv[])
    {
    
        int status = 0;
        int opt;
        static unsigned int udp_port = DEFAULT_UDP_PORT;
        static char serial_device[20] = DEFAULT_SERIAL_PORT;
        static char udp_address[20] = DEFAULT_UDP_ADDRESS;
        static unsigned int heartbeat_freq_ms = 2000;
        static unsigned int mode = 0;
    
        printf("Starting smcpv1-proxy v%s\n", smcp1GetVersion());
    
        while ((opt = getopt(argc, argv, "u:s:p:b:n:h")) != EOF && status == 0)
        {
            bool parseError = false;
            char *endPtr;
            switch (opt)
            {
            case 'u': // UDP address
                strncpy(udp_address, optarg, sizeof(udp_address));
                break;
            case 's': // serial port
                strncpy(serial_device, optarg, sizeof(serial_device));
                break;
            case 'p': // udp port
                udp_port = strtoul(optarg, &endPtr, 10);
                parseError = ((optarg == endPtr) || *endPtr != '\0');
                break;
            case 'n': // notification frequency in ms
                heartbeat_freq_ms = strtoul(optarg, &endPtr, 10);
                parseError = ((optarg == endPtr) || *endPtr != '\0');
                break;
            case 'h':
                printUsage();
                status = 2;
                break;
            case '?': // invalid/unknown option
                fprintf(stderr, "Invalid option '-%c'\n", optopt);
                status = EXIT_FAILURE;
                break;
            default:
                break;
            }
            if (parseError)
            {
                fprintf(stderr, "Invalid value '%s' for option '-%c'\n", optarg, opt);
                status = EXIT_FAILURE;
            }
        }
    
        printf("Starting with values : \n");
        printf("\tUDP address : %s\n", udp_address);
        printf("\tUDP port    : %d\n", udp_port);
        printf("\tSerial port : %s\n", serial_device);
        printf("\tHeartbeat   : %d ms\n", heartbeat_freq_ms);
    
        if (status == 0)
        {
            printf("Proxy initialization...\r");
            fflush(stdout);
            proxyInit(udp_port, serial_device, udp_address);
            printf("Proxy initialization successfull\n");
    
            printf("System initialization...\r");
            fflush(stdout);
            initSystem();
            printf("System initialization successfull\n");
    
            // Create a heartbeat handler
            sa.sa_handler = &heartBeatHandler;
            sigaction(SIGALRM, &sa, NULL);
    
            struct itimerval timer;
    
            timer.it_value.tv_sec = 1; // First timer interval (1 sec)
            timer.it_value.tv_usec = 0;
            timer.it_interval.tv_sec = heartbeat_freq_ms / 1000; // Following timer intervals
            timer.it_interval.tv_usec = (heartbeat_freq_ms % 1000) * 1000;
    
            // Init smcpv1 layer
            printf("About to initializate threads\r");
            fflush(stdout);
            initThreads();
            printf("Threads initialization successfull\n");
    
            // Start the timer
            if (heartbeat_freq_ms)
            {
                setitimer(ITIMER_REAL, &timer, NULL);
            }
    
            PROXY_INIT_COMPLETE = 1;
    
            printf("Proxy is running\n");
            pthread_join(threadUdp, NULL);
            printf("Closing program... Deinitializing proxy");
            proxyDeinit();
            printf("Closing program... Done");
        }
        else
        {
            fprintf(stderr, "Some arguments are incorrect, cannot proceed.\n");
        }
    
        return status;
    }
    
    void printUsage()
    {
        printf("Usage: smcp1_proxy [OPTIONS]\n");
        printf("Options:\n");
        printf("\t-u UDP_ADDRESS\tSpecify the UDP address to use\n");
        printf("\t-s SERIAL_PORT\tSpecify the serial port to use\n");
        printf("\t-p UDP_PORT\t\tSpecify the UDP port to use\n");
        printf("\t-m MODE\t\tSpecify the mode to use\n");
        printf("\t-n NOTIF_FREQ\tSpecify the notification frequency to use, in ms\n");
        printf("\t-h Display this help message\n");
        printf("\nExample:\n");
        printf("\tsmcp1_proxy -u 169.254.255.255 -s /dev/ttyS0 -p 55555\n");
    }
    
    void heartBeatHandler(int signum)
    {
        UNUSED(signum);
        tmclHeartBeatHandler();
    
        // we just "ping" the serial device to know if it is still plugged in.
        int dataWrote = (int)write(serial_fd, NULL, 0);
        if (dataWrote < 0)
        {
            // Handle error: serial device might not be connected, we quit.
            SHOULD_EXIT = 1;
        }
    
        // Prints a changing heartbeat message to display that the program is still live if nothing is happening
        static bool alternate = false;
        if (alternate)
        {
            printf("\theartbeat.  \t\t\r");
        }
        else
        {
            printf("\theartbeat...\t\t\r");
        }
        alternate = !alternate;
        fflush(stdout);
    }
    // Create Threads
    static void *start_Executor(void *argument)
    {
        mcu_executorStart((mcu_event_queue)argument);
    }
    
    mcu_error initThreads()
    {
        // ... init Executor
        mcu_error status = mcu_executorInit();
        assert(status == MCU_ERROR_NONE);
    
        if (status == MCU_ERROR_NONE)
        {
    
            // Executor threads
            printf("Creating thread for communication between motors...");
            int error = pthread_create(&threadExecComm, NULL, start_Executor, (void *)MCU_EVENT_QUEUE_COMM);
            if (error)
            {
                printf("Failed !\n");
            }
            else
            {
                printf("Success\n");
            }
    
            if (!error)
            {
                printf("Creating thread for handling motor1...");
                error = pthread_create(&threadExec0, NULL, start_Executor, (void *)MCU_EVENT_QUEUE_0);
                if (error)
                {
                    printf("Failed !\n");
                }
                else
                {
                    printf("Success\n");
                }
            }
            if (!error)
            {
                printf("Creating thread for handling motor2...");
                error = pthread_create(&threadExec1, NULL, start_Executor, (void *)MCU_EVENT_QUEUE_1);
                if (error)
                {
                    printf("Failed !\n");
                }
                else
                {
                    printf("Success\n");
                }
            }
            if (!error)
            {
                printf("Creating thread for handling motor3...");
                error = pthread_create(&threadExec2, NULL, start_Executor, (void *)MCU_EVENT_QUEUE_2);
                if (error)
                {
                    printf("Failed !\n");
                }
                else
                {
                    printf("Success\n");
                }
            }
            if (!error)
            {
                printf("Creating thread for handling motor4...");
                error = pthread_create(&threadExec3, NULL, start_Executor, (void *)MCU_EVENT_QUEUE_3);
                if (error)
                {
                    printf("Failed !\n");
                }
                else
                {
                    printf("Success\n");
                }
            }
            // UDP thread
            if (!error)
            {
                printf("Creating thread for handling UDP communication with input controller...");
                error = pthread_create(&threadUdp, NULL, readUdp, NULL);
                if (error)
                {
                    printf("Failed !\n");
                }
                else
                {
                    printf("Success\n");
                }
            }
    
            if (error)
            {
                status = MCU_ERROR_NOT_INITIALIZED;
                perror("Failed to create some threads for UDP");
            }
        }
    
        return status;
    }