#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/can.h>
#include <pthread.h>

#define CAN_INTERFACE "can0"
#define TX_INTERVAL_MS 10

// Define the CAN ID to be sent
#define TX_CAN_ID 0x123

// Function to send CAN messages periodically
void* send_can_messages(void* arg) {
    int s;
    struct sockaddr_can addr;
    struct ifreq ifr;
    struct can_frame frame;

    // Create a socket for sending CAN messages
    if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
        perror("Socket creation error");
        return NULL;
    }

    // Set the CAN interface name
    strcpy(ifr.ifr_name, CAN_INTERFACE);
    ioctl(s, SIOCGIFINDEX, &ifr);

    // Configure the CAN socket address
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;

    // Bind the socket to the CAN interface
    if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
        perror("Socket binding error");
        close(s);
        return NULL;
    }

    // Configure the CAN frame to be sent
    frame.can_id = TX_CAN_ID;  // Use the specified CAN ID
    frame.can_dlc = 8;         // Length of data in bytes
    for (int i = 0; i < frame.can_dlc; i++) {
        frame.data[i] = 0x11 + i;  // Adjust the data bytes as needed
    }

    while (1) {
        // Try to send the CAN message
        if (write(s, &frame, sizeof(struct can_frame)) < 0) {
            perror("Write error");
        }

        usleep(TX_INTERVAL_MS * 1000);  // Sleep for TX_INTERVAL_MS milliseconds
    }

    close(s);
    return NULL;
}

// Function to receive and process CAN messages
void* receive_can_messages(void* arg) {
    int s;
    struct sockaddr_can addr;
    struct ifreq ifr;
    struct can_frame frame;

    // Create a socket for receiving CAN messages
    if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
        perror("Socket creation error");
        return NULL;
    }

    // Set the CAN interface name
    strcpy(ifr.ifr_name, CAN_INTERFACE);
    ioctl(s, SIOCGIFINDEX, &ifr);

    // Bind the socket to the CAN interface
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
        perror("Bind error");
        close(s);
        return NULL;
    }

    while (1) {
        int nbytes = read(s, &frame, sizeof(struct can_frame));
        if (nbytes < 0) {
            perror("Read error");
        } else {
            printf("Received CAN message ID 0x%X, Data: ", frame.can_id);
            for (int i = 0; i < frame.can_dlc; i++) {
                printf("%02X ", frame.data[i]);
            }
            printf("\n");
        }
    }

    close(s);
    return NULL;
}

int main() {
    pthread_t tx_thread, rx_thread;

    // Initialize the CAN interface with a baud rate of 1000 kbps
    system("sudo ip link set " CAN_INTERFACE " type can bitrate 1000000");
    system("sudo ifconfig " CAN_INTERFACE " up");

    // Create the TX and RX threads
    if (pthread_create(&tx_thread, NULL, send_can_messages, NULL) != 0) {
        perror("Failed to create TX thread");
        return EXIT_FAILURE;
    }

    if (pthread_create(&rx_thread, NULL, receive_can_messages, NULL) != 0) {
        perror("Failed to create RX thread");
        return EXIT_FAILURE;
    }

    // Wait for the threads to finish (which won't happen in this example)
    pthread_join(tx_thread, NULL);
    pthread_join(rx_thread, NULL);

    return EXIT_SUCCESS;
}
