Загрузка данных


#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <signal.h>
#include <errno.h>

/* Constants matching the M7 core definitions */
#define SRTM_SERVICE_CAMERA_ID   (0x7F)
#define SRTM_VERSION             (0x01)

#define SRTM_CMD_CAMERA_ON       (0x01)
#define SRTM_CMD_CAMERA_OFF      (0x02)

/* SRTM Message Types */
#define SRTM_TYPE_REQUEST        (0x00)
#define SRTM_TYPE_RESPONSE       (0x01)

/* Return codes for response packets (checked by M7 as asyncReq->retCode) */
#define SRTM_CAMERA_RETURN_CODE_SUCCESS (0x00)
#define SRTM_CAMERA_RETURN_CODE_ERROR   (0x01)

/* Macro for poll timeout in milliseconds (-1 means block indefinitely) */
#define POLL_TIMEOUT_MS          (1000) 

/* Global flag for graceful daemon shutdown on signals */
static volatile sig_atomic_t keep_running = 1;

/* Standard SRTM packet header layout */
struct srtm_header {
    uint8_t category;
    uint8_t version;
    uint8_t command;
    uint8_t type;
} __attribute__((packed));

/* Incoming request packet structure from M7 */
struct camera_request {
    struct srtm_header head;
    uint8_t camera_id;
} __attribute__((packed));

/* Outgoing response packet structure to unblock M7 sync execution */
struct camera_response {
    struct srtm_header head;
    uint8_t ret_code; 
} __attribute__((packed));

/* Signal handler for graceful termination */
void signal_handler(int signum) {
    (void)signum;
    keep_running = 0;
}

/* Handler for turning the selected camera stream ON */
void handle_camera_on(uint8_t camera_id) {
    printf("[Linux] Received command: TURN ON camera ID: %d\n", camera_id);
}

/* Handler for turning the selected camera stream OFF */
void handle_camera_off(uint8_t camera_id) {
    printf("[Linux] Received command: TURN OFF camera ID: %d\n", camera_id);
}

int main(int argc, char *argv[]) {
    const char *device = "/dev/rpmsg0"; 
    struct pollfd fds[1];
    int ret;

    if (argc > 1) {
        device = argv[1];
    }

    /* Register signal handlers for clean exit */
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = signal_handler;
    sigaction(SIGINT, &sa, NULL);
    sigaction(SIGTERM, &sa, NULL);

    /* Open the RPMSG device in non-blocking mode */
    int fd = open(device, O_RDWR | O_NONBLOCK);
    if (fd < 0) {
        perror("Failed to open RPMSG device channel");
        return EXIT_FAILURE;
    }

    /* Configure the poll structural array for monitoring incoming data */
    fds[0].fd = fd;
    fds[0].events = POLLIN; /* Monitor for read events */

    printf("SRTM Camera Daemon (Poll-based) initialized on %s. Monitoring requests...\n", device);

    uint8_t rx_buffer[512];
    
    while (keep_running) {
        /* Wait for data on the RPMSG descriptor with a defined timeout */
        ret = poll(fds, 1, POLL_TIMEOUT_MS);

        if (ret < 0) {
            if (errno == EINTR) {
                /* Poll was interrupted by a signal, loop back and check keep_running */
                continue;
            }
            perror("Poll system call execution failed");
            break;
        }

        if (ret == 0) {
            /* Timeout reached with no data; perfect place for periodic background tasks */
            continue;
        }

        /* Verify if the observed descriptor reports readable incoming payload data */
        if (fds[0].revents & POLLIN) {
            ssize_t bytes_read = read(fd, rx_buffer, sizeof(rx_buffer));
            
            if (bytes_read < 0) {
                if (errno == EAGAIN || errno == EWOULDBLOCK) {
                    continue; /* No actual data available, false event trigger */
                }
                perror("Error while reading data from the RPMSG channel");
                break;
            }

            if (bytes_read < (ssize_t)sizeof(struct srtm_header)) {
                fprintf(stderr, "Received a malformed packet (too short: %ld bytes)\n", bytes_read);
                continue;
            }

            struct camera_request *req = (struct camera_request *)rx_buffer;

            /* Verify the service category and check if the packet type is an active Request */
            if (req->head.category == SRTM_SERVICE_CAMERA_ID && req->head.type == SRTM_TYPE_REQUEST) {
                
                uint8_t cam_id = req->camera_id;
                uint8_t cmd = req->head.command;
                uint8_t status_to_send = SRTM_CAMERA_RETURN_CODE_SUCCESS;

                /* Parse and route command IDs */
                if (cmd == SRTM_CMD_CAMERA_ON) {
                    handle_camera_on(cam_id);
                } else if (cmd == SRTM_CMD_CAMERA_OFF) {
                    handle_camera_off(cam_id);
                } else {
                    fprintf(stderr, "Unrecognized Camera Command ID: 0x%02X\n", cmd);
                    status_to_send = SRTM_CAMERA_RETURN_CODE_ERROR;
                }

                /* Construct the mandatory sync Response packet to avoid M7 timeout loops */
                struct camera_response resp;
                resp.head.category = SRTM_SERVICE_CAMERA_ID;
                resp.head.version  = SRTM_VERSION;
                resp.head.command  = cmd;
                resp.head.type     = SRTM_TYPE_RESPONSE; 
                resp.ret_code      = status_to_send;     

                /* Transmit the response payload back to the M7 endpoint link */
                ssize_t bytes_written = write(fd, &resp, sizeof(resp));
                if (bytes_written < 0) {
                    perror("Failed to transmit synchronization response to M7");
                }
            }
        }

        /* Intercept error conditions reported on the monitored file descriptor */
        if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
            fprintf(stderr, "RPMSG file descriptor reported an error or hangup event\n");
            break;
        }
    }

    printf("Shutting down SRTM Camera Daemon cleanly...\n");
    close(fd);
    return EXIT_SUCCESS;
}