2025年3月3日 星期一

家庭代工-1

多個modules,開thread去執行at commands
記錄IMEI+確認FW version
家庭代工用
create by Gemini...
#include <errno.h>
#include <fcntl.h>
#include <libudev.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>

#define TIMEOUT_MS 3000 // Timeout in milliseconds
#define MAX_BUFFER_SIZE 256
#define MAX_AT_RESPONSE 16
#define MAX_DEVICE_PATH 64 // Define a constant for device path size

// Structure to hold AT command and its response time
typedef struct
{
    char command[16];
    double response_time;
} ATCommand;

// Structure to hold the AT command responses
typedef struct
{
    char device_path[MAX_DEVICE_PATH]; // Use the defined constant
    char response[MAX_BUFFER_SIZE];
} DeviceResponse;

DeviceResponse device_responses[MAX_AT_RESPONSE];

pthread_mutex_t response_mutex = PTHREAD_MUTEX_INITIALIZER;
int response_count = 0;

// Function prototypes (for clarity)
int open_serial_port(const char *port_name);
int send_at_command(int fd, const char *command, char *response,
                    size_t response_size, double response_time);
void close_serial_port(int fd);
void *process_device(void *arg);
int find_tty_acm(int argc, char *argv[], int *get_count,
                 char dev_path[][MAX_DEVICE_PATH]); // Use the defined constant
void GetResponseData(char *input, char *output, size_t array_size,
                     int line_sopt);

ATCommand ATCS[] =
{
    {"at", 0.3},      // Example response time of 300ms (converted to seconds)
    {"at+cgsn", 0.4}, // Example response time of 400ms
    {"ati1", 0.4},    // Example response time of 400ms
};

int open_serial_port(const char *port_name)
{
    int fd = open(port_name, O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd == -1)
    {
        perror("open_serial_port: open failed");
        return -1;
    }

    struct termios tty;
    memset(&tty, 0, sizeof(tty));
    if (tcgetattr(fd, &tty) != 0)
    {
        perror("open_serial_port: tcgetattr failed");
        close(fd);
        return -1;
    }

    cfsetospeed(&tty, B115200); // Set baud rate (adjust as needed)
    cfsetispeed(&tty, B115200);

    tty.c_cflag &= ~PARENB; // No parity
    tty.c_cflag &= ~CSTOPB; // 1 stop bit
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;            // 8 data bits
    tty.c_cflag &= ~CRTSCTS;       // No hardware flow control
    tty.c_cflag |= CREAD | CLOCAL; // Enable read and ignore control lines

    tty.c_lflag &= ~ICANON; // Disable canonical mode
    tty.c_lflag &= ~ECHO;   // Disable echo
    tty.c_lflag &= ~ECHOE;  // Disable erasure
    tty.c_lflag &= ~ECHONL; // Disable new-line echo
    tty.c_lflag &= ~ISIG;   // Disable interpretation of interrupt, quit, and
    // suspend characters

    tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Disable software flow control
    tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR |
                     ICRNL); // Disable special handling of received bytes

    tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes
    tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed

    tty.c_cc[VTIME] = TIMEOUT_MS / 100; // Timeout in deciseconds (correct)
    tty.c_cc[VMIN] = 0;                 // Minimum number of characters to receive

    if (tcsetattr(fd, TCSANOW, &tty) != 0)
    {
        perror("open_serial_port: tcsetattr failed");
        close(fd);
        return -1;
    }

    return fd;
}

int send_at_command(int fd, const char *command, char *response,
                    size_t response_size, double response_time)
{
    tcflush(fd, TCIFLUSH); // Flush the input buffer

    ssize_t bytes_written = write(fd, command, strlen(command));
    if (bytes_written < 0)
    {
        perror("send_at_command: write failed");
        return -1;
    }

    memset(response, 0, response_size);
    size_t total_bytes_read = 0;

    struct timeval start_time, current_time;
    gettimeofday(&start_time, NULL); // Use gettimeofday for better precision

    while (total_bytes_read < response_size - 1)
    {
        ssize_t bytes_read = read(fd, response + total_bytes_read,
                                  response_size - 1 - total_bytes_read);
        if (bytes_read < 0)
        {
            if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                gettimeofday(&current_time, NULL);
                double elapsed_time =
                    (current_time.tv_sec - start_time.tv_sec) +
                    (current_time.tv_usec - start_time.tv_usec) / 1000000.0;

                if (elapsed_time > response_time)
                {
                    tcflush(fd, TCIFLUSH); // clear the buffer
                    fprintf(stderr, "send_at_command: Timeout occurred\n");
                    return -1; // Timeout occurred
                }
                usleep(10000); // small delay before retry (10ms)
                continue;      // retry read
            }
            else
            {
                perror("send_at_command: read failed");
                return -1;
            }
        }

        if (bytes_read == 0)
        {
            // End of file or no more data
            break;
        }

        total_bytes_read += bytes_read;
        if (strstr(response, "OK\r\n") != NULL)
        {
            break; // Stop reading when OK is received.
        }
    }

    response[total_bytes_read] = '\0'; // Null-terminate the string
    return 0;
}

void close_serial_port(int fd)
{
    close(fd);
}

void *process_device(void *arg)
{
    int serial_fd;
    char *dev_path = (char *)arg;
    char response[MAX_BUFFER_SIZE];
    int at_command_count =
        sizeof(ATCS) / sizeof(ATCS[0]); // Calculate number of AT commands

    printf("Thread processing device: %s\n", dev_path);
    serial_fd = open_serial_port(dev_path);
    if (serial_fd == -1)
    {
        fprintf(stderr, "Error opening serial port: %s\n", strerror(errno));
        return NULL;
    }

    // Send AT commands
    for (int i = 0; i < at_command_count; i++)
    {
        char command[32]; // Ensure enough space for the command
        snprintf(command, sizeof(command), "%s\r", ATCS[i].command); // Append \r

        if (send_at_command(serial_fd, command, response, sizeof(response),
                            ATCS[i].response_time) == 0)
        {
            printf("Response to '%s': %s\n", ATCS[i].command, response);

            pthread_mutex_lock(&response_mutex);
            if (response_count < MAX_AT_RESPONSE)
            {
                strncpy(device_responses[response_count].device_path, dev_path,
                        MAX_DEVICE_PATH - 1);
                device_responses[response_count].device_path[MAX_DEVICE_PATH - 1] =
                    '\0'; // Ensure null termination

                strncpy(device_responses[response_count].response, response,
                        MAX_BUFFER_SIZE - 1);
                device_responses[response_count].response[MAX_BUFFER_SIZE - 1] =
                    '\0'; // Ensure null termination

                response_count++; // Increment response count

            }
            else
            {
                fprintf(stderr, "Response buffer is full!\n");
            }
            pthread_mutex_unlock(&response_mutex);

        }
        else
        {
            fprintf(stderr, "Error sending command '%s'\n", ATCS[i].command);
        }
    }

    close_serial_port(serial_fd);
    pthread_exit(NULL);
}

int find_tty_acm(int argc, char *argv[], int *get_count,
                 char dev_path[][MAX_DEVICE_PATH])
{
    if (argc != 4)
    {
        fprintf(stderr, "Usage: %s  \n", argv[0]); // Corrected Usage message
        return 1;
    }

    const char *target_vid = argv[1];
    const char *target_pid = argv[2];
    const char *target_bInterfaceNumber = argv[3];

    struct udev *udev = udev_new();
    if (!udev)
    {
        fprintf(stderr, "Failed to create udev object\n");
        return 1;
    }

    struct udev_enumerate *enumerate = udev_enumerate_new(udev);
    udev_enumerate_add_match_subsystem(enumerate, "tty");
    udev_enumerate_add_match_property(enumerate, "ID_VENDOR_ID", target_vid);
    udev_enumerate_add_match_property(enumerate, "ID_MODEL_ID", target_pid);
    udev_enumerate_scan_devices(enumerate);

    struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate);
    struct udev_list_entry *entry;

    int i = 0;
    udev_list_entry_foreach(entry, devices)
    {
        const char *path = udev_list_entry_get_name(entry);
        struct udev_device *dev = udev_device_new_from_syspath(udev, path);
        if (!dev)
        {
            fprintf(stderr, "Error creating udev_device from syspath: %s\n", path);
            continue; // Skip to the next device
        }

        const char *devnode = udev_device_get_devnode(dev);
        const char *bInterface =
            udev_device_get_property_value(dev, "ID_USB_INTERFACE_NUM");

        if (devnode && bInterface &&
                strcmp(bInterface, target_bInterfaceNumber) == 0)
        {
            if (i < MAX_AT_RESPONSE)   // Check for overflow
            {
                strncpy(dev_path[i], devnode, MAX_DEVICE_PATH - 1); // Use strncpy
                dev_path[i][MAX_DEVICE_PATH - 1] = '\0';            // Null-terminate
                printf("Found device: %s\n", devnode);
                i++;
                (*get_count)++;
            }
            else
            {
                fprintf(stderr, "Too many devices found.  Increase MAX_AT_RESPONSE.\n");
                break;
            }
        }
        udev_device_unref(dev);
    }

    udev_enumerate_unref(enumerate); // Free enumerate object
    udev_unref(udev);

    return 0;
}

void GetResponseData(char *input, char *output, size_t array_size,
                     int line_sopt)
{
    char *line, *saveptr;
    int stop = 0;

    output[0] = '\0'; // Initialize output string

    line = strtok_r(input, "\n", &saveptr);
    while (line != NULL)
    {
        if (stop == line_sopt)
        {
            strncpy(output, line, array_size - 1); // Use strncpy for safety
            output[array_size - 1] = '\0';         // Ensure null termination
            return;
        }
        line = strtok_r(NULL, "\n", &saveptr);
        stop++;
    }
    output[0] = '\0'; // If line_sopt is out of range, return an empty string
}

int main(int argc, char *argv[])
{
    int device_count = 0;
    char dev_path[MAX_AT_RESPONSE]
    [MAX_DEVICE_PATH];     // Array to store device paths
    pthread_t threads[MAX_AT_RESPONSE]; // Array to store thread IDs
    int thread_creation_result;

    if (find_tty_acm(argc, argv, &device_count, dev_path) != 0)
    {
        fprintf(stderr, "find_tty_acm failed\n");
        exit(EXIT_FAILURE);
    }

    printf("Loop count: %d\n", device_count);
    if (device_count == 0)
    {
        printf("No devices found. Exiting.\n");
        exit(EXIT_SUCCESS);
    }

    // Create threads for each device found
    for (int i = 0; i < device_count; i++)
    {
        printf("Creating thread for device: %s\n", dev_path[i]);
        thread_creation_result =
            pthread_create(&threads[i], NULL, process_device, (void *)dev_path[i]);
        if (thread_creation_result != 0)
        {
            fprintf(stderr, "ERROR; return code from pthread_create() is %d\n",
                    thread_creation_result);
            exit(EXIT_FAILURE);
        }
    }

    // Wait for all threads to complete
    for (int i = 0; i < device_count; i++)
    {
        pthread_join(threads[i], NULL);
    }

    // Write responses to file
    FILE *fp = fopen("device_responses.txt", "w");
    if (fp == NULL)
    {
        perror("Error opening file");
        exit(EXIT_FAILURE);
    }

    char imei[16];
    char fw[64];

    for (int i = 0; i < device_count; i++)   // Iterate through each device
    {
        memset(imei, 0, sizeof(imei));
        memset(fw, 0, sizeof(fw));

        // Find the responses for the current device
        char *imei_response = NULL;
        char *fw_response = NULL;

        for (int j = 0; j < response_count; j++)
        {
            if (strncmp(device_responses[j].device_path, dev_path[i],
                        MAX_DEVICE_PATH) == 0)
            {
                // Match the Device Path
                if (strstr(device_responses[j].response, "at+cgsn") != NULL)
                {
                    imei_response = device_responses[j].response;
                }
                else if (strstr(device_responses[j].response, "ati1") != NULL)
                {
                    fw_response = device_responses[j].response;
                }
            }
        }

        if (imei_response)
        {
            GetResponseData(imei_response, imei, sizeof(imei), 1);
            fprintf(fp, "IMEI: %s", imei);
        }
        else
        {
            fprintf(fp, "IMEI: Not found\n");
        }

        if (fw_response)
        {
            GetResponseData(fw_response, fw, sizeof(fw), 3);
            if (strlen(fw) > 0)
            {
                if (strstr(fw, "REVISION 02.000") != NULL)
                {
                    fprintf(fp, ", OK    , FW: %s", fw);
                }
                else
                    fprintf(fp, ", FAILED, FW: %s", fw);

            }
            else
            {
                fprintf(fp, "FW: Not found\n");
            }
        }
        else
        {
            fprintf(fp, "FW: Not found\n");
        }
        fprintf(fp, "\n"); // Add a new line to separate devices.
    }

    fclose(fp);
    printf("All threads completed. Responses written to device_responses.txt\n");
    exit(EXIT_SUCCESS);
}

Compile
gcc find_modules.c -o find_modules -Wall -Wextra -pthread -ludev

$ ./find_modules 1e2d 0069 04

沒有留言:

張貼留言