#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <net/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>

#include <linux/can.h>
#include <linux/can/raw.h>

#include "dy_common.h"
#include "dy_can.h"

void *can_receive_loop(void *param)
{
    can_cfg_t *can_cfg = (can_cfg_t *)param;
    int i = 0, j = 0;
    int nfds;

    while (1)
    {
        nfds = epoll_wait(can_cfg->epollfd, can_cfg->events, MAXEPOLLSIZE, FRAME_TIMEOUT);
        if (nfds == 0)
        {
            // no fd ready
            continue;
        }
        else if (nfds > 0)
        {
            for (i = 0; i < nfds; i++)
            {
                // 输入事件
                if (can_cfg->events[i].events & EPOLLIN)
                {
                    pthread_mutex_lock(&can_cfg->recv_lock);
                    for (j = 0; j < can_cfg->node_cnt; j++)
                    {
                        if (can_cfg->events[i].data.fd == can_cfg->can_dev[j].fd)
                        {
                            struct can_frame frame;
                            int ret = 0;
                            int count = 0;

                            while (1)
                            {
                                ret = recv(can_cfg->events[i].data.fd, &frame, sizeof(struct can_frame), MSG_DONTWAIT);
                                if (ret < 0)
                                {
                                    if (errno == EINTR)
                                    {
                                        continue;
                                    }
                                    else if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
                                    {
                                        break;
                                    }
                                    else
                                    {
                                        dy_syslog(LOG_INFO, "nread errno %d", errno);
                                        break;
                                    }
                                }

                                else if (ret > 0)
                                {
                                    can_frame_node_t *node = malloc(sizeof(can_frame_node_t));
                                    if (node == NULL)
                                    {
                                        dy_syslog(LOG_ERR, "malloc can frame node failed");
                                        continue;
                                    }
                                    memcpy(&node->frame, &frame, sizeof(struct can_frame));
                                    node->port = can_cfg->can_dev[j].port;
                                    list_add_tail(&node->list, &can_cfg->can_dev[j].rcv_list);
                                    can_cfg->received = 1;

                                    count++;
                                    if (count > 100)
                                    {
                                        break;
                                    }
                                }
                                else
                                {
                                    break;
                                }
                            }
                            break;
                        }
                    }
                    pthread_mutex_unlock(&can_cfg->recv_lock);
                }
            }
            if (can_cfg->received)
            {
                pthread_cond_signal(&can_cfg->recv_cond);
            }
        }
        else
        {
            dy_syslog(LOG_ERR, "wrong in epoll_wait");
            break;
        }
    }
    dy_syslog(LOG_ERR, "something wrong happened in can thread!!!");
    return NULL;
}
